学习 React 已快有 3 个月了,在这里通过分享学习心得,与大家一起交流,与大家一起每天进步。
在刚开始学习 React 的时候,我认为组件的 state 或者 props 改变时,就会触发组件的 render 函数执行。后来我通过一系列的试验发现,state 不改变也可以触发 render 函数的执行,props 改变了也不一定触发 render 函数的执行,下面通过一系列的 demo 说明这个观点。
state不改变也可以触发render函数的执行
直接上代码:
import React from 'react';
import ReactDOM from 'react-dom';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
message: 'click button',
};
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
console.log('Click happen');
this.setState({});
}
render() {
console.log('App render');
const { message } = this.state;
return (
<button onClick={ this.handleClick }>{ message }</button>
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
代码的思路很简单,按钮绑定一个点击事件,当点击按钮时,执行 setState({}) 方法,由于 setState 方法的参数是一个空对象,state 并没有改变,这时候观察 render 函数是否执行,结果是执行了的,如下图,所以,只要 setState 方法执行,render 函数就会执行。
props改变了也不一定触发render函数的执行
直接上代码:
import React, {Fragment} from 'react';
import ReactDOM from 'react-dom';
const obj = {
message: 'hello world',
};
class App extends React.Component {
handleClick() {
console.log('click happen');
obj.message = 'hello Beijing';
}
render() {
return (
<Fragment>
<button onClick={ this.handleClick }>Click</button>
<Component1 objMessage={ obj } />
</Fragment>
);
}
}
class Component1 extends React.Component {
render() {
const { objMessage } = this.props;
console.log('Component1 render');
return (
<div>{ objMessage.message }</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
代码思路很简单,一个父组件 App,一个子组件 Component1,子组件的props来自于外部变量 obj,当我点击父组件的按钮时,去改变外部变量 obj 对象的值,这时候去观察子组件 Component1 的 render 函数是否执行,结果是没有执行,如下图,所以 props 改变了也不一定触发 render 函数的执行。
总结
在 React 中,只要执行了 setState 方法,就一定会触发 render 函数执行;组件的 props 改变了,不一定触发 render 函数的执行,除非 props 的值来自于父组件或者祖先组件的 state,在这种情况下,组件的 props 改变,也就意味着父组件或者祖先组件的 state 发生了改变,也就是父组件或者祖先组件执行了 setState 方法;那么可以总结出,render 函数的执行时机就是 setState 方法的执行。
另,render 函数执行并不一定意味着发生 DOM 操作,render 函数执行只是返回虚拟 DOM,需要通过比较新旧虚拟 DOM 来决定是否发生 DOM 操作,新旧虚拟 DOM 的比较,就涉及 diff 算法了,这又是另一个话题了。