回顾:
根据目前学习内容,更新界面内容的方法为ReactDOM.render()
//定义一个方法tick,包含组件和渲染
function tick(){
const element = <h1>{new Date().toLocalTimeString()}</h1>
ReactDOM.render(
element,document.getElementById('root')
)
}
//运行方法,每秒钟重新构建元素和渲染,计时器效果
setInterval(tick,1000);
本次目的:实现clock组件的封装和可重用
1.将函数转换成class
①创建一个名为React.Component的ES6类
②创建一个render()的空方法
③把函数体移动到render(){}方法中
④在render方法中,使用this.props替换props
⑤删除剩余的空函数声明
class Clock extends React.Component{
render(){
return(
<div>
<h1>{this.props.date.toLocaleTimeString()}</h1>
</div>
)
}
}
ReactDOM.render(
<Clock date={new Date()} />,
document.getElementById('root')
)
现在Clock被定义为一个类,而不只是一个函数,
使用类就允许我们使用它的特性,例如局部状态,生命状态钩子。
1.为了一个类添加局部状态
①将date从属性中转移到状态中
②在render()
方法张使用this.state.date
代替this.props.date
③添加一个类构造函数来初始化State,类组件应始终用props调用基础构造函数
④在Clock
组件中,去除date
属性
class Clock extends React.Component{
constructor(){
super(props);
this.state = {date:new Date()};
}
render(){
return(
<h1>it is {this.state.date.toLocalTimeString()}</h1>
)
}
}
ReactDOM.render(
<Clock />,document.getElementById('root')
)
2.将生命周期方法添加到类中
在具有许多组件的应用程序中,销毁时释放组件所占用的资源非常重要。
每当Clock
组件加载到DOM中,都会想要用它生成一个定时器,在React中被称为挂载
同样,每当Clock
生成的这个DOM被移除时,就需要清除定时器,这被称为 卸载。
可以在组件中生命一些方法,当组件 挂载 或者 卸载时执行。
class Clock extends React.Component{
constructor(props){
super(props);
this.state = {date:new Date()};
}
componentDidMount(){
console.log('挂载开始')
this.timerID = setInterval(()=>{
this.tick();
},1000)
}
componentWillUnmounte(){
console.log('结束')
clearInterval(this.timerID);
}
tick(){
this.setState({
date:new Date()
})
}
render(){
return(
<div>
<h1>{this.state.date.toLocaleTimeString()}</h1>
</div>
)
}
}
ReactDOM.render(
<Clock />,
document.getElementById('root')
)
以上的componentDidMount()
和componentWillUnmount()
方法被称为生命周期钩子
当组件输出到DOM后会执行componentDidMount()
方法,这时候适合建立一个定时器
步骤如下:
①当 <Clock />
被传递给 ReactDOM.render()
时,React 调用 Clock 组件的构造函数。 由于 Clock 需要显示当前时间,所以使用包含当前时间的对象来初始化 this.state
。即this.state={date:new Date()};
②React 然后调用 Clock 组件的 render()
方法。把React 更新 DOM 以匹配 Clock 的渲染输出。
③当 Clock 的输出插入到 DOM 中时,React 调用 componentDidMount()
生命周期钩子。 在其中,Clock 组件要求浏览器设置一个定时器,每秒钟调用一次 tick(),此时DOM已经构建好,类似vue的mounted()
。
④浏览器每秒钟调用 tick()
方法。 在其中,Clock 组件通过使用包含当前时间的对象调用 setState()
来调度UI更新。 通过调用 setState()
,React 知道状态已经改变,并再次调用 render()
方法来确定屏幕上应当显示什么。 这一次,render()
方法中的 this.state.date
将不同,所以渲染输出将包含更新的时间,并相应地更新DOM。
⑤一旦Clock组件被从DOM中移除,React会调用componentWillUnmount()
这个钩子函数,定时器也就会被清除。
从中可知:
修改this.state
状态需要使用this.setState({})
方法,这里有点类似微信小程序的设置方式。
3.正确的使用状态
关于this.setState({})
的几个重点
①更新状态或者this.state中的内容
this.setState({comment:'hello'}); //正确修改方式
this.state.comment='hello' //错误方式
this.state.comment //获取state状态中的内容
②构造函数是唯一能够初始化this.state
的地方
③状态的更新可能是异步操作导致的
React可以将多个setState({})调用合并成一个来提高性能。
因为this.props
和this.state
可能是异步更新的,所以不应该根据这个来计算下一个状态的值,因为可能不是最新的数据。
这里使用第二种形式
让setState({})
接收一个方法,而不是一个对象,其中包含2个参数,先前的状态state作为第一个参数,应用被更新时的props作为第二个参数
// 错误的方式,计算的结果不是最新的
this.setState({
counter: this.state.counter + this.props.increment,
});
// 正确的方式
this.setState((prevState,props)=>{
counter:prevState.counter+props.increment
})
4.状态的更新并合并
当使用this.setState
的时候,React会将当前的提供的对象合并到当前状态
状态中可能包含一些独立的变量
constructor(props){
super(props);
this.state({
posts:[],
comment:[]
})
}
此时,可以分别调用```this.setState···独立调用他们
componentDidMount() {
fetchPosts().then(response => {
this.setState({
posts: response.posts
});
});
fetchComments().then(response => {
this.setState({
comments: response.comments
});
});
}
5.数据的自顶向下流动
父组件或者子组件都不能知道其他组件是否有状态state,以及组件是被定义为一个class类还是函数。
除了拥有并且设置他的组件外,其他组件不可访问内部状态。
组件可以选择将他的状态作为属性传递给其他子组件。通过this.state来获取
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
也适用于用户自定义的组件
<hello date={this.state.date} />
其中hello组件收到的date属性值,并不知道是来自Clock组件的属性还是状态。
这通常被称为 自顶向下的数据流,或者是单向数据流。任何状态始终只在某些特定的组件中,并且该状态的导出的数据或者UI视图,也只能影响 树 下方的组件。
DEMO
为了证明所有组件都是隔离的,先创建一个组件<App />
class App extends React.Component{
render(){
return(
<div>
<Clock />
<Clock />
<Clock />
</div>
)
}
}
ReactDOM.render(
<App />,document.getElementById('root')
)
其中的每一个<Clock />
会建立自己的组件并且独立更新。
网友评论