



外部数据一般都是来自父元素的内部数据:

初始化:



让props的主人对数据进行更改:


黑话:帮会、盗匪、流氓团伙等所使用的只有同伙才能听懂的暗语 -> 钩子,只有程序员才能听懂的暗语!
import "./styles.css";
import React from "react";
export default class App extends React.Component {
constructor() {
super();
this.state = {
n: 0
};
}
onClick = () => {
this.setState({
n: this.state.n + 1
});
};
render() {
return (
<div className="App">
App <button onClick={this.onClick}>+1</button>
<B name={this.state.n}>
<h1>1</h1>
<h2>2</h2>
</B>
</div>
);
}
}
class B extends React.Component {
// constructor(props) {
// super(props);
// console.log(props);
// }
componentWillReceiveProps(newProps, nextContext) {
console.log("旧的 props");
console.log(this.props);
console.log("props 变化了");
console.log("新的 props");
console.log(newProps);
}
render() {
return (
<div>
{this.props.name}
<div>{this.props.children}</div>
</div>
);
}
} //通过 this.props.xxx 读取

该钩子的作用就是「通知你
props什么时候变化」
注意,componentWillReceiveProps钩子已被弃用 -> 请不要使用!

💡:为什么要么不写constructor,要么写全constructor?我没有写constructor,而我在 JSX 是可以直接使用this.props拿到外部对象的?
如果你不写 constructor,那么 React 内部,会在组件实例化后,执行这行代码:
// React 内部
const instance = new YourComponent(props);
instance.props = props;




不守规矩的写 State:

需求:两次 setState

this.state.x在读的时候,还是旧的x值

之前说过了,函数可以延迟求值,而这个
this.state.x是先确定了值再给setState的! -> 第一个setState执行后,x并咩有变化,还是原来的1,当执行到第二个setState,this.state.x的值依旧是1
所以,如何让两次setState的结果是两次+1呢?
三种姿势:
setState -> 这样就只写一次setState了setTimeout()=>{ two setState } -> 在 callback 里边写两次 setStatesetState的需求用定时器:

这种姿势的
setState看上去就像同步了! -> 如果不加setTimeout就是异步了! -> 总之,setState本质还是异步的!
用函数参数:

其实还可以用setState的第二个参数来搞(少用):

💡:为什么要多次setState?
因为这个 Web 应用程序变复杂了,所以多次 setState 就可能出现了!
然而一个setState就意味着一次render?即 DOM 视图会立刻发生变化吗? -> 不 -> 这是「batches updates」,也就是先把你要更新的说清楚,再一次性去render -> 类似于,你要买 10 个苹果,但你却一个袋子装一个这样去结账,结账了 10 次! -> 为何不 10 个装在一起,再一次性结账呢?
为什么要用函数参数? -> 我们需要用到上一次setState的结果!
类比「王牌对王牌:传声筒传话游戏」:

💡:为什么用了函数参数后,第二个setState的state值就是上一个setState更新后的值?
💡:setState的源码?
ReactComponent.prototype.setState = function(partialState, callback) {
this.updater.enqueueSetState(this, partialState);
if (callback) {
this.updater.enqueueCallback(this, callback, 'setState');
}
};
partialState -> 部分state -> 表示「不影响其它的state,只更新我要更新的」
原生 JS 里边的生命周期:

React 里边的生命周期:

我们必须要会的钩子:

componentWillUnmount-> 组件将要消失!


什么时候触发这个钩子? -> state变了就触发

如果我们没有用shouldComponentUpdate,即便n的值还是原来的1,也会执行render方法,因为state已经变了,state这个对象换了,那么 React 就得更新数据,当然,这并不会更新 UI:

总之,你不写shouldComponentUpdate去处理的话,render是多执行了的,而我们用这个生命周期钩子是可以阻止它执行的!
如何阻止? -> 判断新的旧的相等就不执行

示例代码:

💡:pureComponent?
它会在 render 之前对新旧 state 进行对比(浅对比,只对比一层)

如果你多此一举的写了shouldComponentUpdate,那么控制台就会警告你:

面对这种情况:

pureComponent也就不好使了!即name依旧是frank,还是会调用render,当然,这 UI 并不会更新!
总之:

它给 React 使用者的印象:
return的是一个 vDOM 对象



可以简写成三目运算符:

如果你想只展示一种,那么你可以简写成&&:

如果你用for循环,你这样写:
class() {
render() {
for (let index = 0; index < this.state.arr.length; index++) {
const element = this.state.arr[index];
return element
}
}
}
循环一遍就结束,因为return了呀!
返回的是数组,而不是一个数组元素:

Warning: Each child in a list should have a unique "key" prop-> 别忘了,要为每个 react 元素加一个唯一的key属性
使用map(更高级),而不是for:

组件已经挂载了!

需求:拿到一个元素的width,并把它显示页面!
组件被挂载之后才能拿到:

如果你在创建的时候拿这个div元素,那它就是个null了:

总之,我们可以在componentDidMount这个钩子里边发起 Ajax 请求,当然,也可以在constructor里边发,之所以选择在componentDidMount里边发请求,实属偏好! -> 如果面试问「在哪儿发 Ajax 请求?」,你就会回到说在componentDidMount里边发,因为官方推荐哈!
注意:这个钩子没有参数
💡:使用 ref 姿势获取节点?

更新 UI 后执行

注意点:
prevProps 之前的 props、prevState 之前的 State、snapshot关于第三个参数:如果组件实现了
getSnapshotBeforeUpdate()生命周期(不常用),则它的返回值将作为componentDidUpdate()的第三个参数 “snapshot” 参数传递。否则此参数将为undefined。

💡:面试官问:请问我要发起一个 Ajax 请求,在哪里可以发起比较好?
在
componentDidMount()里面发起比较好
面试官再问:请问还有没有其它钩子可以加载数据(发起 Ajax)?
如果有必要的话在
componentDidUpdate()里面也可以发起请求,只不过请求是用来更新数据的,所以这个钩子显然不能这样做,因为这样很没有意义!
将死之人(页面中移除,内存也要清除)



函数列表:

正确的认识:
组件的state变了,就是指组件实例的state属性变了(遵守不可变数据理念),而不是说state旗下的那些属性变了!