在项目开发的过程中,遇到了一个问题:

父组件请求后台数据,收到后将数据以props传给子组件,子组件根据收到数据的不同,显示不同的内容,同时,子组件自身可以根据click操作改变根据父组件的数据显示的内容。

因此,子组件收到父组件的props传值后,由于props值不能修改,因此子组件需要将该props值放入state,子组件根据自身click操作改变state,进而改变组件显示的内容。

而父组件传过来的值,子组件在componentDidMount中无法获取,可以在render中获取。但是若将获取值的部分写在render中,会导致页面每次更新都从父组件拿值,子组件的click操作修改值无法起作用。

子组件代码如下:

class child extends PureComponent {
static propTypes = {
value: PropTypes.bool.isRequired
};
constructor(props) {
super( props);
this.state = {
value: false
};
}
changeValue = () => {
this.setState({
value: false
});
}
render() {
this.state = {
value: this.props.value
};
return (
<div style={{ display: value ? 'block':'none' }}>
<img src={src} alt="" />
<div className={styles.value}>这是父组件的传值:{value}</div>
<div className={styles['icon-close']} onClick={this.changeValue}>
<img src={close} alt="" />
</div>
</div>
);
}
}
export default Child;

解决方法1:将click的close方法写在render中

但该写法不是很规范,render() 函数应该是纯粹的,也就是说该函数不修改组件state,每次调用都返回相同的结果,不读写 DOM 信息,也不和浏览器交互(例如通过使用 setTimeout)。

class child extends PureComponent {
static propTypes = {
value: PropTypes.bool.isRequired
};
constructor(props) {
super( props);
this.state = {
value: false
};
}
render() {
this.state = {
value: this.props.value
};
changeValue = () => {
this.setState({
value: false
});
}
return (
<div style={{ display: value ? 'block':'none' }}>
<img src={src} alt="" />
<div className={styles.value}>这是父组件的传值:{value}</div>
<div className={styles['icon-close']} onClick={changeValue}>
<img src={close} alt="" />
</div>
</div>
);
}
}
export default Child;

解决方法2:使用componentWillReceiveProps

class child extends PureComponent {
static propTypes = {
value: PropTypes.bool.isRequired
};
constructor(props) {
super( props);
this.state = {
value: false
};
}
componentWillReceiveProps(nextProps) {
this.setState({
value: nextProps.value
});
}
changeValue = () => {
this.setState({
value: false
});
}
render() {
return (
<div style={{ display: value ? 'block':'none' }}>
<img src={src} alt="" />
<div className={styles.value}>这是父组件的传值:{value}</div>
<div className={styles['icon-close']} onClick={this.changeValue}>
<img src={close} alt="" />
</div>
</div>
);
}
}
export default Child;

总结:

react组件的生命周期

  • componentWillMount
  • componentDidMount
  • componentWillReceiveProps
  • shouldComponentUpdate
  • componentWillUpdate
  • componentDidUpdate 
  • componentWillUnmount

1. componentWillMount 组件将要挂载

组件刚经历constructor,初始完数据

在初始化渲染执行之前立刻调用,服务器端和客户端都只调用一次

组件还未进入render,组件还未渲染完成,dom还未渲染

如果在这个方法内调用setState,render() 将会感知到更新后的state,将会执行仅一次,尽管 state 改变了。

2. componentDidMount 组件渲染完成

在初始化渲染执行之后立刻调用一次,仅客户端有效(服务器端不会调用)

此时dom节点已经生成,可以在这里调用ajax请求,返回数据setState后组件会重新渲染

在生命周期中的这个时间点,组件拥有一个DOM 展现,你可以通过 this.getDOMNode() 来获取相应 DOM 节点

可以在这个方法中调用setTimeout, setInterval或者发送AJAX请求等操作(防止异步操作阻塞UI)

3.componentWillReceiveProps (nextProps)

在组件接收到一个新的 prop (更新后)时被调用。这个方法在初始化render时不会被调用。

在接受父组件改变后的props需要重新渲染组件时用到的比较多

用此函数可以作为react 在 prop 传入之后, render() 渲染之前更新 state 的机会。

在该函数中调用 this.setState() 将不会引起第二次渲染。

通过对比nextProps和this.props,将nextProps setState为当前组件的state,从而重新渲染组件

componentWillReceiveProps (nextProps) {
nextProps.openNotice !== this.props.openNotice && this.setState({
openNotice:nextProps.openNotice
},() => {
console.log(this.state.openNotice:nextProps) //将state更新为nextProps,在setState的第二个参数(回调)可以打印出新的state
})
}

4. shouldComponentUpdate(nextProps,nextState)

唯一用于控制组件重新渲染的生命周期

由于在react中,setState以后,state发生变化,组件会进入重新渲染的流程(暂时这么理解,其实setState以后有些情况并不会重新渲染,比如数组引用不变)。react父组件的重新渲染会导致其所有子组件的重新渲染,这个时候其实我们是不需要所有子组件都跟着重新渲染的,因此需要在子组件的该生命周期中做判断。在这里return false可以阻止组件的更新

如果 shouldComponentUpdate 返回false,则 render() 将不会执行,直到下一次 state 改变。(另外,componentWillUpdate 和 componentDidUpdate 也不会被调用。)

在接收到新的props 或者 state,将要渲染之前调用。该方法在初始化渲染的时候不会调用,在使用 forceUpdate 方法的时候也不会。

默认情况下,shouldComponentUpdate 总会返回true,在 state 改变的时候避免细微的bug,但是如果总是小心地把 state 当做不可变的,在 render() 中只从 props 和state 读取值,此时你可以覆盖 shouldComponentUpdate 方法,实现新老 props 和state 的比对逻辑。

如果性能是个瓶颈,尤其是有几十个甚至上百个组件的时候,使用 shouldComponentUpdate可以提升应用的性能。

5. componentWillUpdate (nextProps,nextState)

在组件接收到新的props或者state但还没有render时被调用。在初始化时不会被调用。

shouldComponentUpdate返回true以后,组件进入重新渲染的流程,进入componentWillUpdate,这里同样可以拿到nextProps和nextState

你不能在该方法中使用this.setState()。如果需要更新state来响应某个prop的改变,可使用componentWillReceiveProps。

6. componentDidUpdate(prevProps,prevState)

在组件完成更新后立即调用。在初始化时不会被调用。

组件更新完毕后,react只会在第一次初始化成功会进入componentDidmount,之后每次重新渲染后都会进入这个生命周期

在组件的更新已经同步到DOM 中之后立刻被调用。

这里可以拿到prevProps和prevState,即更新前的props和state。

使用该方法可以在组件更新之后操作DOM 元素。

为了兼容 v0.9,DOM节点会作为最后一个参数传入。如果使用这个方法,你仍然可以使用 this.getDOMNode() 来访问 DOM 节点。

7.componentWillUnmount()

在组件从DOM 中移除的时候立刻被调用。

在该方法中执行任何必要的清理,比如无效的定时器,或者清除在 componentDidMount 中创建的 DOM 元素,移除所有组建中的监听 removeEventListener

除此之外,

8.constructor

constructor参数接受两个参数props,context,可以获取到父组件传下来的的props,context,

如果你想在constructor构造函数内部使用props或context,则需要传入,并传入super对象。

只要组件存在constructor,就必要要写super,否则this指向会错误

9. render函数

render函数会插入jsx生成的dom结构,react会生成一份虚拟dom树,

在每一次组件更新时,在此react会通过其diff算法比较更新前后的新旧DOM树,比较以后,找到最小的有差异的DOM节点,并重新渲染

react16中 render函数允许返回一个数组,单个字符串等,不在只限制为一个顶级DOM节点,可以减少很多不必要的div

组件生命周期的执行顺序:

在react的组件挂载及render过程中,最底层的子组件是最先完成挂载及更新的。

constructor()构造函数、componentWillMount执行顺序:顶层父组件 ->子组件 ->子组件 ->底层子组件

render、componentDidMount顺序:底层子组件 ->子组件 ->子组件 ->顶层父组件

以下是http://www.runoob.com菜鸟教程上面的一个实例:

class Button extends React.Component {
constructor(props) {
super(props);
this.state = {data: };
this.setNewNumber = this.setNewNumber.bind(this);
} setNewNumber() {
this.setState({data: this.state.data + })
}
render() {
return (
<div>
<button onClick = {this.setNewNumber}>INCREMENT</button>
<Content myNumber = {this.state.data}></Content>
</div>
);
}
} class Content extends React.Component {
componentWillMount() {
console.log('Component WILL MOUNT!')
}
componentDidMount() {
console.log('Component DID MOUNT!')
}
componentWillReceiveProps(newProps) {
console.log('Component WILL RECEIVE PROPS!')
}
shouldComponentUpdate(newProps, newState) {
return true;
}
componentWillUpdate(nextProps, nextState) {
console.log('Component WILL UPDATE!');
}
componentDidUpdate(prevProps, prevState) {
console.log('Component DID UPDATE!')
}
componentWillUnmount() {
console.log('Component WILL UNMOUNT!')
} render() {
return (
<div>
<h3>{this.props.myNumber}</h3>
</div>
);
}
}
ReactDOM.render(
<div>
<Button />
</div>,
document.getElementById('example')
);

运行结果:

(控制台info)

点击按钮:

参考:https://www.jianshu.com/p/c9bc994933d5

https://www.jianshu.com/p/ee122bb5b14b

http://www.runoob.com/react/react-component-life-cycle.html

https://blog.csdn.net/limm33/article/details/50942808

react学习(6)——关于组件生命周期的问题的更多相关文章

  1. React(四)组件生命周期

    组件的生命周期可分成三个状态: Mounting:已插入真实 DOM Updating:正在被重新渲染 Unmounting:已移出真实 DOM 生命周期的方法有: componentWillMoun ...

  2. [React] 多组件生命周期转换关系

    前段时间一直在基于React做开发,最近得空做一些总结,防止以后踩坑. 言归正传,React生命周期是React组件运行的基础,本文主要是归纳多组件平行.嵌套时,生命周期转换关系. 生命周期 Reac ...

  3. React.js 小书 Lesson20 - 更新阶段的组件生命周期

    作者:胡子大哈 原文链接:http://huziketang.com/books/react/lesson20 转载请注明出处,保留原文链接和作者信息. 从之前的章节我们了解到,组件的挂载指的是将组件 ...

  4. React组件生命周期小结

    React组件生命周期小结 下面所写的,只适合前端的React.(React也支持后端渲染,而且和前端有点小区别,不过我没用过.) 相关函数 简单地说,React Component通过其定义的几个函 ...

  5. React—组件生命周期详解

    React—组件生命周期详解 转自 明明的博客  http://blog.csdn.net/slandove/article/details/50748473 (非原创) 版权声明:转载请注明出处,欢 ...

  6. 1.4 React 组件生命周期

    1.4.1 组件 React 中组件有自己的生命周期方法,简单理解可以为组件从 出生(实例化) -> 激活 -> 销毁 生命周期 hook.通过这些 hook 方法可以自定义组件的特性. ...

  7. React 之 组件生命周期

    React 之 组件生命周期 理解1) 组件对象从创建到死亡它会经历特定的生命周期阶段2) React组件对象包含一系列的勾子函数(生命周期回调函数), 在生命周期特定时刻回调3) 我们在定义组件时, ...

  8. AngularJs学习笔记-组件生命周期

    组件生命周期 (1)组件生命周期钩子 constructor:组件创建时被创建 ngOnChanges: 父组件修改或初始化子组件的输入属性时被调用,如果子组件没有输入属性,则永远不会被调用,它的首次 ...

  9. vue 学习一 组件生命周期

    先上一张vue组件生命周期的流程图 以上就是一个组件完整的生命周期,而在组件处于每个阶段时又会提供一些周期钩子函数以便我们进行一些逻辑操作,而总体来讲 vue的组件共有8个生命周期钩子 beforeC ...

随机推荐

  1. thinkphp 3.2 updateFields 设置之后保存失败

    // 检测提交字段的合法性 if(isset($this->options['field'])) { // $this->field('field1,field2...')->cre ...

  2. Android中的消息机制:Handler消息传递机制 分类: H1_ANDROID 2013-10-27 22:54 1755人阅读 评论(0) 收藏

    参考<疯狂android讲义>第2版3.5 P214 一.背景 出于性能优化考虑,Android的UI操作并不是线程安全的,这意味着如果有多个线程并发操作UI组件,可能导致线程安全问题.为 ...

  3. 嵌入式linux串口通信自发自收测试程序

     /*串口自收自发程序主函数*/#include"uart_api.h"int main(){ int fd; char buff[BUFFER_SIZE]; char buff2 ...

  4. Android多线程研究(8)——Java5中Futrue获取线程返回结果

    我们先来看一下ExecutorService中的执行方法: 在上一篇中我们使用了execute方法启动线程池中的线程执行,这一篇我们来看看submit方法的使用:submit提交一个返回值的任务用于执 ...

  5. 无法为数据库中的对象分配空间,因为'PRIMARY'文件组已满

    用SQL Server2012,做数据保存时出错,错误信息:无法为数据库'***'中的对象'***'分配空间,因为'PRIMARY'文件组已满.请删除不需要的文件.删除文件组中的对象.将其他文件添加到 ...

  6. SendMessageTimeout 的使用

    在WINDOW编程中,发送消息的常用API有SendMessage,PostMessage,PostThreadMessage. 一般每个线程有两个队列:一个用来接收通过Send函数的消息,另外一个队 ...

  7. Net Core 实现谷歌翻译ApI 免费版

    原文:Net Core 实现谷歌翻译ApI 免费版 由于谷歌翻译官方API是付费版本,本着免费和开源的精神.分享一下用 Net Core 实现谷歌翻译API的代码. 项目引用的Nuget 包: Cha ...

  8. 【b304】传染病防治

    Time Limit: 1 second Memory Limit: 50 MB [问题背景] 近来,一种新的传染病肆虐全球.蓬莱国也发现了零星感染者,为防止该病在蓬莱国 大范围流行,该国政府决定不惜 ...

  9. 【22.70%】【codeforces 591C】 Median Smoothing

    time limit per test2 seconds memory limit per test256 megabytes inputstandard input outputstandard o ...

  10. JEECG 什么是商业版本的功能最近添加的好友?

    JEECG 商业版本号近期新增什么功能啦? 2014-12-18 JEECG JEECG jeecg添加新的功能啦! !. 1.流程设计器 2.集成工作流引擎activit,智能化封装,在线配置表单, ...