在这里我们点击按钮时,调用 handleClick 函数,首先调用 this.setState() 设置 value, 随即把 this.state.value 输出,结果是什么?你可能会想,这还不简单——"在 handleClick 里输出 1" 呗,然而你错了,它的结果为:事实上,setState() 的调用是异步的,这意味着,虽然你调用了 setState({value:0}),但 this.state.value 并不会马上变成 0,而是直到 render() 函数调用时,setState() 才真正被执行。结合图说明一下:你可能又会问了:要是我在 render() 前多次调用 this.setState() 改变同一个值呢?(比如 value) 我们对 handleClick 做一些修改,让它变得复杂一点,在调用 handleClick 的时候,依次调用 handleStateChange1 ,handleStateChange2,handleStateChange3,它们会调用 setState 分别设置 value 为 1,2,3 并且随即打印
- class MyComponent extends React.Component {
- constructor(props) {
- super(props) this.state = {
- value: 0
- }
- }
- handleClick = () = >{
- this.setState({
- value: 1
- }) console.log('在handleClick里输出' + this.state.value);
- }
- render() {
- console.log('在render()里输出' + this.state.value);
- return (this.handleClick
- } > 按钮)
- }
- }
- export
- default MyComponent //省略渲染过程,下面也一样
那么输出结果会是什么呢?如果 setState 是同步调用的,那么结果显然为在 handleClick 里输出 1 在 handleClick 里输出 2 在 handleClick 里输出 3 但是结果为:,证明它是异步的这下好理解了吧,配合这幅图:
- handleStateChange1 = () = >{
- this.setState({
- value: 1
- }) console.log('在handleClick里输出' + this.state.value);
- }
- handleStateChange2 = () = >{
- this.setState({
- value: 2
- }) console.log('在handleClick里输出' + this.state.value);
- }
- handleStateChange3 = () = >{
- this.setState({
- value: 3
- }) console.log('在handleClick里输出' + this.state.value);
- }
- handleClick = () = >{
- this.handleStateChange1();
- this.handleStateChange2();
- this.handleStateChange3();
- }
2. 如何在子组件中改变父组件的 state 呢?
这是我们经常会遇到的问题之一,解决办法是:在父组件中写一个能改变父组件 state 的方法,并通过 props 传入子组件中点击子组件 Son,内容由 a 变成 b,说明父组件的 state 被修改了3.context 的运用,避免 "props 传递地狱"3.1 假设一个比较极端的场景:你需要从你的子组件里调用父父父父父组件的属性或方法,怎么办!当组件嵌套层级过深的时候,不断地传 props 作为实现方式简直就是噩梦!我称之为 "props 传递地狱"(这个词是我瞎编的,参考自 "回调函数地狱") 我们接下来实现的是这样一个需求,把 gene 属性(基因)从组件 GrandFather -->Father --> Son 传递,如果用 props 传递:
- class Son extends React.Component {
- render() {
- return (this.props.handleClick
- } > {
- this.props.value
- })
- }
- }
- class Father extends React.Component {
- constructor(props) {
- super(props) this.state = {
- value: 'a'
- }
- }
- handleClick = () = >{
- this.setState({
- value: 'b'
- })
- }
- render() {
- return (this.state.value
- }
- handleClick = {
- this.handleClick
- }
- />
- )
- }
- }/
demo:【(。・ `ω´ ・) 虽然听起来有点怪怪的但是大家别介意哈】实现是实现了,但你想想,假设不是从 "爷爷" 组件,而是从 "太太太太爷爷" 组件传下来,这多可怕!不过没关系,react 提供了一个叫做 context(上下文) 的 API,你在顶层组件的 context 中定义的属性,可以在所有的后代组件中,通过 this.context. 属性去引用!让我们一睹为快:
- class Son extends React.Component {
- render() {
- return (我从我的爷爷那里得到了基因--{
- this.props.gene
- })
- }
- }
- class Father extends React.Component {
- render() {
- return (this.props.gene
- }
- />)
- }
- }
- class GrandFather extends React.Component{
- constructor(props) {
- super(props)
- this.state ={
- gene:'[爷爷的基因]'
- }
- }
- render(){
- return (this.state.gene}/ > )
- }
- }
demo 效果同上!这个时候你发现,我们在 <GrandFather> 组件和 <Father> 组件中都没有向下传递 props,我们就从最下层的 Son 组件中获取了 gene 属性,是不是很方便! 解释下代码:getChildContext() 是你在顶层组件中定义的钩子函数,这个函数返回一个对象——你希望在后代组件中取用的属性就放在这个对象中,譬如这个例子中我希望在 Son 组件中通过 this.context.gene 取属性,所以在 getChildContext() 中返回 {gene:'[爷爷的基因]'}GrandFather.childContextTypes 和 Son.contextTypes 用于规定顶层组件和取顶层组件 context 的后代组件的属性类型【注意】GrandFather.childContextTypes 和 Son.contextTypes 这两个对象必须要规定!否则 context 只能取到空对象!一开始我犯的这个错误简直让我狂吐三升血。。。。有图有真相之 context 和 props 的区别3.2context 是否推荐使用?虽然上面这个例子说明了 context 多么好用,但注意:官方并不推荐经常使用它,因为它会让你的应用架构变得不稳定 (官方文档原话 If you want your application to be stable, don't use context), 在我看来,为什么在大多数情况下要使用 props 而不是实现数据流呢,因为 props 凭借组件和组件间严密的逻辑联系,使得你能够清晰地跟踪应用的数据流(it's easy to track the flow of data through your React components with props) 当然了,如果你遇到上述的例子的情况,context 还是大有裨益的 3.3 需要改变 context 中的属性时候,不要直接改变它,而是使用 this.state 作为媒介,如果你试图在顶层组件的 state 中放入一个可变的属性你可以这样做:
- class Son extends React.Component {
- render() {
- console.log(this.context.color);
- return (我从我的爷爷那里得到了基因--{
- this.context.gene
- })
- }
- }
- Son.contextTypes = {
- gene: React.PropTypes.string
- }
- class Father extends React.Component {
- render() {
- return ()
- }
- }
- class GrandFather extends React.Component {
- getChildContext() {
- return {
- gene: '[爷爷的基因]'
- }
- }
- render() {
- return ()
- }
- }
- GrandFather.childContextTypes = {
- gene: React.PropTypes.string
- };
- export
- default GrandFather
3.4 在上述我限制 gene 的类型时候我是这样写的:gene: React.PropTypes.string,使用了 React 内置的 React.PropTypes 帮助属性,此时我的版本为 "react": "15.4.2", 在 15.5 的版本后这一帮助属性被废弃,推荐使用 props-types 库,像这样:
- getChildContext() {
- return {
- type: this.state.type
- }
- }
当然,在这之前你需要 npm install prop-types4 组件类里有私有变量 a,它到底改放在 this.a 中还是 this.state 对象中(作为属性 a)呢?这得根据它是否需要实时的重渲染决定,如果该变量需要同步到变化的 UI 中,你应该把它放在 this.state 对象中,如果不需要的话,则把它放在 this 中(无代码无 demo)【完】-- 喜欢这篇文章的话不妨关注一下我哟
- const PropTypes = require("Prop-Types");
- GrandFather.childContextTypes = {
- gene: PropTypes.string
- };
来源: http://www.cnblogs.com/penghuwan/p/6718850.html