本文详细解析 React 面向组件编程中的三大核心属性:state、props 和 refs。通过对比函数组件与类组件,深入讲解 state 的状态管理与更新机制、props 的单向数据流与类型校验,以及 refs 获取 DOM 节点的三种方式,帮助开发者掌握 React 组件的核心交互逻辑。
前言
- React 组件内部默认封装了多个属性,其中部分供开发者操作。在这之中,state、props 和 refs 是三个至关重要的核心属性。熟练掌握这三大属性的使用,是实现组件状态更新与交互的基础。
一、组件的基本理解与使用
1. 函数组件
<script type="text/babel">
function MyComponent() {
return <h2>我是函数定义的组件(适用于简单组件的定义)</h2>
}
ReactDOM.render(<MyComponent />, document.getElementById('test'))
</script>
函数组件的渲染流程如下:React 解析组件标签并定位到对应组件;由于该组件由函数定义,React 会调用该函数以生成虚拟 DOM;最后,React 将虚拟 DOM 转换为真实 DOM 并渲染至页面中。
1.React解析了组件标签,找到了对应的组件
2.发现这个组件是一个函数定义的,随后调用该函数,生成一个虚拟dom
3.最后将虚拟dom转化成为真实dom,呈现在页面中
2. 类式组件
<script type="text/babel">
class MyComponent extends React.Component {
render() {
return <h2>我是类定义的组件适用于复杂数据类型</h2>
}
}
ReactDOM.render(<MyComponent />, document.getElementById('test'))
</script>
类式组件的渲染流程相对复杂:React 解析标签并找到对应的类组件;随后通过 new 关键字实例化该组件,并调用实例原型上的 render 方法;render 方法返回的内容被生成为虚拟 DOM;最终,虚拟 DOM 被转换为真实 DOM 并展示在页面上。
1.React解析了组件标签,找到了对应的组件
2.发现这个组件是一个类定义的,随后new出来一个实例对象,并通过该实例调用原型上的render方法
3.将render()返回的内容生成一个虚拟dom
4.最后将虚拟dom转化成为真实dom,呈现在页面中
3. 组件注意事项
组件名必须首字母大写
虚拟DOM元素只能有一个根元素
虚拟DOM元素必须有结束标签
二、组件的三大核心属性
1. state
state是一个对象,用于存储组件的数据状态。当状态发生变化时,会触发视图的重新渲染。其作用机制与Vue中的data对象类似。
<script type="text/babel">
class Weather extends React.Component {
constructor() {
super()
this.state = {
isHot: false,
wind: '微风'
}
this.chang = this.chang.bind(this)
}
render() {
let { isHot, wind } = this.state
return <h2 onClick={this.chang}>今天的天气很 {isHot ? "炎热" : "凉爽"},{wind}</h2>
}hang() {
console.log(this)
this.setState({
isHot: !this.state.isHot
})
}
}
ReactDOM.render(<Weather />, document.getElementById('test'))
</script>
1. 注意事项
1.组件中render方法中的this为组件实例对象
2.组件自定义的方法中this为undefined,如何解决?
1.强制绑定this: 通过函数对象的bind()
2.箭头函数
3.状态数据,不能直接修改或更
2. 简写方式
<script type="text/babel">
class Weather extends React.Component {
state = {
isHot: false,
wind: '微风'
}
render() {
let { isHot, wind } = this.state
return <h2 onClick={this.chang}>今天的天气很 {isHot ? "炎热" : "凉爽"},{wind}</h2>
}
chang = ()=>{
this.setState({
isHot: !this.state.isHot//这里的修改是一种合并,对比属性的变化,如果有赋新值,没有则跳过
})
}
}
ReactDOM.render(<Weather />, document.getElementById('test'))
let a = new Weather()
</script>
设置状态:setState
setState(object nextState[, function callback])
严禁在组件内部直接通过 this.state 修改状态,因为直接赋值后调用 setState() 会导致状态被覆盖替换。
调用 setState() 并不会立即更新 this.state,而是创建一个待处理的 state 对象。setState() 的执行不一定是同步的,为了优化性能,React 会批量执行 state 和 DOM 的渲染过程。
setState() 总是会触发一次组件重绘,除非在 shouldComponentUpdate() 中实现了特定的条件渲染逻辑以阻止更新。
2. props
- 在
React中,组件通过 props 属性接收外部传入的数据,这一点与 Vue 框架的设计思路一致。 - React 中提到的单向数据流即指 props,基于这一特性,props 还承担着另一个重要角色:
组件之间的通信。 - props 本身是
不可变的的,但存在一种看似可变的情形:当父组件的 state作为子组件的 props时,若父组件的 state 发生改变,子组件接收到的 props 也会随之更新。这实际上依然遵循了props 是不可更改的这一核心定律。
<script type="text/babel">
class MyComponent extends React.Component {
render() {
return (
<ul>
<li>{this.props.name}</li>
<li>{this.props.age}</li>
</ul>
);
}
}
ReactDOM.render(
<MyComponent name="Bob" age="18" />,
document.getElementById("test")
);
</script>
props 的主要特点如下:
- 每个组件对象都拥有 props(properties 的缩写)属性。
- 组件标签上的所有属性均保存在 props 对象中。
- 在组件内部读取特定属性值时,使用 this.props.propertyName。
- 其作用是从组件外部向内部传递数据,且该数据为只读(read only)。
- 支持对 props 中的属性值进行类型限制和必要性校验。
对 props 进行限制
- 需要引入 prop-type 库,这是专门用于限制 props 属性的工具库。
- 在当前页面导入 prop-type 库。
- 通过 Person.propTypes = {} 的形式进行属性限制。
class MyComponent extends React.Component {
render() {
return (
<ul>
<li>{this.props.name}</li>
<li>{this.props.age}</li>
</ul>
);
}
}
// 校验类型
MyComponent.propTypes = {
name: PropTypes.string, // 这里的 PropTypes 变量是全局挂载的
age: PropTypes.number,
};
ReactDOM.render(
<MyComponent name="Bob" age={18} />,
document.getElementById("test")
);
props 的简写用法
<script type="text/babel">
class Weather extends React.Component {
constructor(props) {//是否接受,取决于是否使用外部数据
super(props)//只能上面接受了props,super()就去传递,否则后续的使用,可能就会出现问题
}
static propTypes = {
name: PropTypes.string.isRequired,//限制name为字符串类型,必填
// age: PropTypes.number,
sex: PropTypes.string,
speak: PropTypes.func
}
static defaultProps = {
sex: '男',
}
render() {
let { name, age, sex } = this.props
return (
<ul>
<li>姓名:{name}</li>
<li>性别:{sex}</li>
<li>年龄:{age + 1}</li>
</ul>
)
}
}
ReactDOM.render(<Weather name="tom" age={26} sex="女" />, document.getElementById('test'))
</script>
函数组件中使用 props
<script type="text/babel">
// 函数组件
function MyComponent(props) {
return (
<ul>
<li>{props.name}</li>
<li>{props.age}</li>
</ul>
);
}
// 校验类型
MyComponent.propTypes = {
name: PropTypes.string,
age: PropTypes.number,
};
ReactDOM.render(
<MyComponent name="Bob" age={18} />,document.getElementById("test")
);
</script>
3. refs
- React 中的 Refs 提供了一种访问 DOM 节点的方式,主要包含三种使用模式:字符串方式、回调函数方式以及 createRef。
- 在 React 中,Refs 允许用户在 render 方法中创建的 React 元素或 DOM 节点之外,访问这些元素。
- 在 React 的单向数据流体系中,props 是父子组件交互的唯一途径。若要修改子组件,必须通过传递新的 props 来触发重新渲染。
然而,在某些特定场景下,需要在数据流之外强制修改子组件。被修改的目标可能是一个 React 组件实例,也可能是一个普通的 DOM 元素。针对这两种情况,React 均通过 Refs 提供了具体的解决方案。
回调函数方式
<script type="text/babel">
class MyComponent extends React.Component {
handleAlert = () => {
// 直接从组件实例上获取 myInput
console.log(this.myInput); // <input type="text">
alert(this.myInput.value);
};
render() {
return (
<div>
{/* ref 直接定义成一个回调函数,参数就是节点本身,将它赋值给组件的一个 myInput 属性 */}
<input ref={(ele) => (this.myInput = ele)} type="text" />
<button onClick={this.handleAlert}>alert</button>
</div>
);
}
}
ReactDOM.render(<MyComponent />, document.getElementById("test"));
</script>
React 官方提示:
如果 ref 回调函数以内联函数形式定义,在更新过程中它会被执行两次:第一次传入参数 null,第二次传入 DOM 元素。这是因为每次渲染都会创建新的函数实例,导致 React 清空旧 ref 并设置新 ref。通过将 ref 的回调函数定义为 class 的绑定函数,可以避免此问题,但在大多数情况下,这种差异并不影响最终结果。
createRef - 官方推荐方式
<script type="text/babel">
class MyComponent extends React.Component {
// 创建 ref
myInput = React.createRef();
handleAlert = () => {
console.log(this.myInput.current); // 这里需要注意,元素是在 current 属性上
alert(this.myInput.current.value);
};
render() {
return (
<div>
{/* 将创建好的 ref 附加到元素上 */}
<input ref={this.myInput} type="text" />
<button onClick={this.handleAlert}>alert</button>
</div>
);
}
}
ReactDOM.render(<MyComponent />, document.getElementById("test"));
</script>
上述内容展示了使用 React.createRef() 方法创建 ref 的方式。需特别注意,创建出的 ref 值是一个对象,所需的 DOM 元素位于该对象的 current 属性上,例如 this.myInput.current。
总结
以上内容涵盖了 React 面向组件编程中的关键部分。希望本文能为您的学习提供帮助。
关于 JavaScript 中 React 面向组件编程的介绍至此结束。如需了解更多相关内容,请搜索本站往期文章或继续浏览后续文章,感谢大家的支持!