初识React (二) 之组件三大核心属性
一、state
1. state 是组件对象最重要的属性, 值是对象(可以包含多个key-value的组合) 2. 组件被称为"状态机", 通过 setState 更新组件的 state 从而来更新对应的页面显示(重新渲染组件) 3. 每调用一次 setState,就会重新执行 render 函数,根据最新的 State 来创建 ReactElement 对象;然后再根据最新的 ReactElement 对象,对 DOM 进行修改
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>React</title>
</head>
<body>
<div id="app"></div>
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
<script type="text/babel">
class ShowAndHidden extends React.Component {
constructor(props){
super(props)
this.state = {
isShow: true,
showStr : 'hello word!'
}
}
triggle=()=>{
this.setState({
isShow: !this.state.isShow
})
}
render() {
return (
<div>
{this.state.isShow && <p>{this.state.showStr}</p>}
<button onClick={this.triggle}>{this.state.isShow ? '隐藏': '显示'}</button>
</div>
);
}
}
ReactDOM.render(<ShowAndHidden />,document.getElementById('app'))
</script>
</body>
</html>
1. 若想要通过事件修改状态时,就需要使用到 setState 方法
2. 同步 or 异步
setState 方法到底是同步还是异步分两种情况
- 在组件生命周期或React事件中,setState是异步, eg:
<script type="text/babel">
class ShowAndHidden extends React.Component {
constructor(props){
super(props)
this.state = {
isShow: true,
showStr : 'hello word!'
}
}
triggle=()=>{
this.setState({
isShow: !this.state.isShow
})
console.log(this.state.isShow); // true
}
componentDidMount(){
this.setState({showStr: '哈哈哈哈'})
console.log('componentDidMount:',this.state.showStr) // 'componentDidMount:' hello word!
}
render() {
return (
<div>
<p>{this.state.showStr}</p>
<button onClick={this.triggle}>点击</button>
</div>
);
}
}
ReactDOM.render(<ShowAndHidden />,document.getElementById('app'))
</script>
结果:
此时在使用 setState 方法后,再打印 isShow 和 showStr,发现 isShow 和 showStr 没有被改变,由此可以看到 setState 是异步操作,在执行完 setState 之后不能够立刻拿到最新的state的结果
- 在setTimeout或者原生dom事件中,setState是同步,eg:
<script type="text/babel">
class ShowAndHidden extends React.Component {
constructor(props){
super(props)
this.state = {
isShow: true,
showStr : 'hello word!'
}
}
// setTimeout
triggle=()=>{
setTimeout(() => {
this.setState({
showStr: "hhhh"
});
console.log('@@',this.state.showStr); // '@@' hhhh
}, 0);
}
// 原生DOM事件
componentDidMount() {
const btn = this.refs.btn;
btn.addEventListener('click', () => {
this.setState({
showStr: "abcd"
});
console.log(this.state.showStr); // abcd
})
}
render() {
return (
<div>
<p>{this.state.showStr}</p>
<button onClick={this.triggle}>点击</button>
<button ref="btn">点击btn</button>
</div>
);
}
}
ReactDOM.render(<ShowAndHidden />,document.getElementById('app'))
</script>
结果:
3. 如何获取更新后的值
- 上面两种在setTimeout或者原生dom事件中
- setState 接受两个参数:第二个参数是一个回调函数,这个回调函数会在更新后会执行
triggle=()=>{
this.setState({
showStr: "hhhh"
},()=>{
console.log('@@',this.state.showStr); // hhhh
});
}
4. setState的合并
class ShowAndHidden extends React.Component {
constructor(props){
super(props)
this.state = {
isShow: true,
showStr : 'hello word!'
}
}
triggle=()=>{
this.setState({
showStr: 'hhhh'
},()=>{
console.log('@@',this.state); // @@ {isShow: true, showStr: 'hhhh'}
});
}
// 通过setState修改showStr,不会对 isShow 产生影响的
render() {
return (
<div>
<p>{this.state.showStr}</p>
<button onClick={this.triggle}>点击</button>
<button onClick={this.handleClick}>点击1</button>
</div>
);
}
}
// 多个 setState 合并
handleClick=()=>{
this.setState({
showStr: '哈哈'
},()=>{
console.log('@@',this.state); // @@ {isShow: true, showStr: '哈哈哈哈'}
});
this.setState({
showStr: '哈哈哈'
},()=>{
console.log('@@',this.state); // @@ {isShow: true, showStr: '哈哈哈哈'}
});
this.setState({
showStr: '哈哈哈哈'
},()=>{
console.log('@@',this.state); // @@ {isShow: true, showStr: '哈哈哈哈'}
});
}
render() {
return (
<div>
<button onClick={this.handleClick}>点击</button>
</div>
);
}
若要执行多次,setState 传入一个函数 返回一个对象
handleClick=()=>{
this.setState((state,props)=>{
return {
num: state.num+1
}
},);
this.setState((state,props)=>{
return {
num: state.num+1
}
});
this.setState((state,props)=>{
return {
num: state.num+1
}
},()=>{
console.log('@@',this.state.num);
});
}
render() {
return (
<div>
<button onClick={this.handleClick}>点击</button>
</div>
);
}
5. 总结:
setState 为什么要异步更新?
- 可以显著提升性能,如果每次调用 setState 都进行一次更新,render 函数会被频繁调用,界面重新渲染,导致效率低,所以获取到多个更新,然后进行批量的更新
- 如果同步更新了 state,但是还没有执行 render 函数,那么 state 和 props 不能保持同步
二、props
1. 每个组件对象都会有props(properties的简写)属性 2. 组件标签的所有属性都保存在props中
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>React</title>
</head>
<body>
<div id="app"></div>
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
<script type="text/babel">
class Person extends React.Component {
constructor(props){
super(props)
console.log(this.props); // {name: '前端代码仔', age: 100, sex: '男'}
console.log(this.props.name); // 前端代码仔
}
render() {
return (
<div>
<h1>props</h1>
</div>
)
}
}
ReactDOM.render(<Person name='前端代码仔' age={100} sex='男'/>,document.getElementById('app'))
</script>
</body>
</html>
1. 通过标签属性从组件外向组件内传递变化的数据 或 使用扩展属性: 将对象的所有属性通过props传递
<Person name='前端代码仔' age={100} sex='男'/>
或
const person = {
name: '前端代码仔',
age: 18,
sex: '男'
}
ReactDOM.render(<Person {...person}/>,document.getElementById('app'))
2. 内部读取某个属性 this.props.属性名 eg: this.props.name
3. 对 props 中的属性值进行类型限制和必要性限制
// 第一种方式(React v15.5 开始已弃用)
Person.propTypes = {
name: React.PropTypes.string.isRequired,
age: React.PropTypes.number,
sex: React.PropTypes.string
}
或
// 第二种方式 使用prop-types库进限制(需要引入prop-types库)
Person.propTypes = {
name: PropTypes.string.isRequired,
age: PropTypes.number,
sex: PropTypes.string
}
4. 默认属性值
Person.defaultProps = {
name: '前端仔'
age: 18,
sex: '男
注意!!! 组件内部不要修改props数据; 函数类型限制要用
PropTypes.func
三、refs
组件内的标签可以定义ref属性来标识自己
1. 字符串形式的ref
<button ref="btn">点击btn</button>
2. 回调形式的ref
<button ref={(currentNode)=> {this.btn = currentNode} }>点击btn</button>
3. createRef 创建 ref 容器
btn = React.createRef()
<button ref={this.btn} >点击btn</button>
转载自:https://juejin.cn/post/7161064742348406814