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

父组件请求后台数据,收到后将数据以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. python没有++和--操作

  2. 一个Exception catch不住的【异常】

    现象: Controller中的方法接收到前台ajax请求后开始执行, 当执行到某一行时程序终止,前台回调进Error方法. 后台明明catch了Exception异常,但异常并没有被捕获(不进cat ...

  3. VCS编译仿真警告Warning

    VCS编译仿真警告Warning 问题描述 在较大的SOC集成中,通常使用Perl脚本例化子模块到Top层,然而,有时会出现例化出来的输入端口名没有在Top层定义,而且端口的位宽为1bit,那么,ve ...

  4. HTML Email 编写指南(转)

      作者: 阮一峰 日期: 2013年6月16日 今天,我想写一个"低技术"问题. 话说我订阅了不少了新闻邮件(Newsletter),比如JavaScript Weekly.每周 ...

  5. 基于 Android NDK 的学习之旅-----序言

    前些日子做了个Android项目, 引擎层 用C的, 准备写这个系类的文章,借此跟朋友来分享下我NDK开放的经验以及自己知识的总结和备忘.希望能给需要这方面资料的朋友提供一定的帮助. 主要涉及到:   ...

  6. 适合前端开发的 Chrome 扩展有哪些?(十款)

    适合前端开发的 Chrome 扩展有哪些?(十款) 一.总结 好的插件或者框架对程序员的意义重大. 二.适合前端开发的 Chrome 扩展有哪些?(十款) 掘金是一个高质量的技术社区,从 ECMASc ...

  7. 【poj 1704】Georgia and Bob

    Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 9776 Accepted: 3222 Description Georgia a ...

  8. 简体和繁体加起来有六七万个汉字,所以Unicode只能排除一些几乎不用的汉字,Unicode编码的熟悉与研究过程(内附全部汉字编码列表)

    我有一个问题是:是不是会有个别汉字无法在Unicode下表示,这种情况下就不能完全显示了? 各种编码查询表:http://bm.kdd.cc/ ---------------------------- ...

  9. spring security之httpSecurity 专题

    37.5.2 Resolving the CsrfToken Spring Security provides CsrfTokenArgumentResolver which can automati ...

  10. 记排查octopress生成时的编码错误

    前些日子经若亮童鞋提醒,我在其他推荐的页面中增加了对 Dropbox 和 Linode 等工具的推荐,一来分享这些好用的产品,二来期望刚接触这些工具的好心的朋友可以不吝啬时间用我的推荐码注册,让我获得 ...