核心属性
注意,本章主要以类式组件为例,记录 React 中的核心属性与方法
state
描述
state 是组件对象最重要的属性,值是对象(可以包含多个 key-value 的组合)
组件被称为“状态机”,通过更新组件的 state 来更新对应的页面显示(重新渲染组件)
注意
组件中 render 方法中的 this 为组件实例对象
组件自定义的方法中 this 为 undefined,如何解决?
- 方案一:强制绑定 this,通过函数对象的 bind()
- 方案二:箭头函数
更新
state 中存放的是状态数据,不能直接修改或更新
需使用原型方法setState()
来切换状态,this.setState({ flag: 'xxx' })
,属于状态对象合并
Component 组件示例
import { Component } from "react";
export default class Count extends Component {
state = {
count: 0,
};
add = () => {
this.setState({ count: this.state.count + 1 });
};
render() {
return (
<div>
<div>{this.state.count}</div>
{/* 注意,此处禁止写 this.state.count++,因为自增运算符是对原count值的修改,React禁止对state的直接修改 */}
<button onClick={this.add}>计数按钮</button>
</div>
);
}
}
props
描述
每个组件对象都会有 props(properties)属性
组件标签的所有属性都保存在 props 中
注意
props 是通过标签属性从组件外部向组件内部传递变化的数据(自上而下的数据通信)
子组件内部不要修改 props 数据
操作
- 子组件读取 props
- 对 props 中的属性值进行类型限制和必要性限制
第一种方式(弃用)
// 类名外部写法
Person.propTypes = {
name: React.PropTypes.string.isRequired,
age: React.PropTypes.number,
};
// 类名内部写法
class Person {
static propTypes = {
name: React.PropTypes.string.isRequired,
age: React.PropTypes.number,
};
}
第二种方式(推荐,使用 prop-types 库进限制(需要引入 prop-types 库))
// 类名外部写法
Person.propTypes = {
name: PropTypes.string.isRequired,
age: PropTypes.number.
}
// 类名内部写法
class Person {
static propTypes = {
name: PropTypes.string.isRequired,
age: PropTypes.number,
}
}
- 扩展运算
将对象的所有属性通过 props 传递
<Person {...person}></Person>
- 默认属性
Person.defaultProps = {
age: 18,
sex: "男",
};
- 组件类的构造函数
// 组件初始化时可以对props进行操作
constructor(props) {
super(props);
console.log(props);
}
- 函数式组件可传入 props,但不可使用 state 属性
function App(props) {
const { name, age, msg } = props;
return <div>名字:{name}</div>;
}
Component 组件示例
import React, { Component } from "react";
import Item from "../item/index";
import "./index.css";
class ToDoList extends Component {
state = {
listState: true,
};
render() {
const toDoList = {
handleData: this.props.handleData,
listState: this.state.listState,
};
return (
<ul className="doList">
{this.props.toDoList.map((item) => {
return <Item key={item.id} {...toDoList} content={item} />;
})}
</ul>
);
}
}
export default ToDoList;
import React, { Component } from "react";
import "./index.css";
class Item extends Component {
render() {
const { id, value, checked } = this.props.content;
const listState = this.props.listState;
const handleData = this.props.handleData;
return (
<li>
<input
onChange={handleData({ eventId: id, flag: listState })}
type="checkbox"
checked={checked}
/>
<p
suppressContentEditableWarning
contentEditable={true}
onBlur={handleData({ eventId: id, flag: listState, mod: true })}
className="doContent"
>
{value}
</p>
<div
onClick={handleData({ eventId: id, flag: listState, del: true })}
className="removeList"
>
-
</div>
</li>
);
}
}
export default Item;
refs
描述
组件内的标签可以定义 ref 属性来标识自己
注意
在 render 函数中,ref 指向的组件如this.refs.xxx
为 undefined,因为此时组件尚未挂载,ref 指向为空
操作
- 字符串形式的 ref(建议弃用)
<input ref="input1" />
- 回调形式的 ref
<input ref={(c)=>{this.input1 = c}}>
- createRef 创建的 ref 容器(建议使用)
myRef = React.createRef()
<input ref={ this.myRef } />
Component 组件示例
import { Component, createRef } from "react";
export default class Count extends Component {
count = createRef();
add = () => {
this.count.current.innerText++;
};
render() {
return (
<div>
<div ref={this.count}>0</div>
{/* 注意,此处禁止写 this.state.count++,因为自增运算符是对原count值的修改,React禁止对state的直接修改 */}
<button onClick={this.add}>计数按钮</button>
</div>
);
}
}
三大属性执行次数
render 调用 N+1 次,第一次为初始化,每次修改调用都会重新调用 render
state 执行 N 次,render 初始化时赋值 state 初始值,每次修改都会重新设置 state(如果 state 涉及修改的话)
props 受父组件影响,父组件执行 N 次则 props 执行 N 次(如果 props 涉及修改的话)
回调 ref 以内联函数的方式定义,在更新过程中被执行两次,第一个传入参数为 null,第二次再传入 DOM 元素。所以目前最推荐的还是React.createRef()
方法