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

父组件请求后台数据,收到后将数据以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. dmalloc arm-linux平台使用

    话说“工欲善其事,必先得其器”,用C语言写程序,最怕遇到个什么内存泄漏,内存越界访问了,心里那个急啊... 如果在i368-linlux上,valgrind工具是首选,但在arm-linux平台上,如 ...

  2. tplink-如何远程WEB管理路由器?

    http://service.tp-link.com.cn/detail_article_185.html 如何远程WEB管理路由器? 新版tplink怎么远程Web管理? https://www.1 ...

  3. css3-1 css3游戏介绍、css3样式和优先级

    css3-1 css3游戏介绍.css3样式和优先级 一.总结 一句话总结:我们写外部css表的时候可以用class,那样使用的人用id修改的话优先级就比我们高,达到目的. 1.html嵌套css样式 ...

  4. BZOJ 1699 [Usaco2007 Jan]Balanced Lineup排队 线段树

    题意:链接 方法:线段树 解析: 题意即题解. 多次询问区间最大值与最小值的差.显然直接上线段树或者rmq维护区间最值就可以. 代码: #include <cstdio> #include ...

  5. 基于 Android NDK 的学习之旅-----Android.mk 介绍

    一个Android.mk file用来向编译系统描述你的源代码.具体来说:该文件是GNU Makefile的一小部分,会被编译系统解析一次或多次.你可以在每一个Android.mk file中定义一个 ...

  6. 【codeforces 760B】Frodo and pillows

    time limit per test1 second memory limit per test256 megabytes inputstandard input outputstandard ou ...

  7. 非常实用全面的 C++框架,库类等资源

    这次的资源涉及到了标准库.Web应用框架.人工智能.数据库.图片处理.机器学习.日志.代码分析等,C++程序员学习必备! Jason frozen : C/C++的Jason解析生成器 Jansson ...

  8. [CSS] Get up and running with CSS Grid Layout

    We’ll discuss the display values pertinent to CSS Grid Layout – grid, inline-grid, and subgrid. Then ...

  9. 囚徒困境、价格大战与 iPhone 的价格

    静态/动态,完全/不完全: 完全信息静态博弈: 不完全信息静态博弈: 完全信息动态博弈: 不完全信息动态博弈: 囚徒困境实际上反映了一个深刻的哲学问题:个人利益与集体利益的矛盾.个人为了自己利益的最大 ...

  10. UITableView的一些常用设置和代理方法

    - (void)viewDidLoad { [super viewDidLoad]; tableview = [[UITableView alloc]initWithFrame:CGRectMake( ...