反应16.3+正确触发方式改变状态变化

时间:2018-05-07 19:23:19

标签: javascript reactjs

所以我有这个组件:

import React from 'react';
import PropTypes from 'prop-types';
import { isEqual } from 'lodash';

class SomeComponent extends React.Component {
  static propTypes = {
    onChange: PropTypes.func,
  };

  previousItems = [];

  constructor(props) {
    super(props);
    this.state = {
      items: ['some', 'list'],
    };
  }

  setState(stateSetter) {
    super.setState(previousState => {
      const newState = stateSetter(previousState);

      if (!isEqual(newState.items, this.previousItems)) {
        this.props.onChange && this.props.onChange(newState.items);
        this.previousItems = newState.items;
      }

      return newState;
    });
  }
}

而我正在尝试做的是听取状态变化并在状态发生变化时触发onChange。我曾经使用componentWillUpdate做到这一点,但我听说React 17会改变。

现在正确的做法是什么?我上面所做的事情让人觉得很难过。

谢谢!

2 个答案:

答案 0 :(得分:2)

Check the docs for componentDidUpdate()

这是副作用发生的地方,如ajax调用或在这种情况下,调用onChange,但你必须检查道具是否真的改变了(就像你在代码中所做的那样)。

请注意,此方法不会在初始渲染中调用,仅在下次更新时调用。非常适合onChange活动。

请注意,如果onChange方法设置状态,它可以启动无限循环(fire onChange - > set state - > fire onChange - > ....)。如有必要,检查状态/道具改变了什么,并仅在必要时触发onChange事件(避免无限循环)。

答案 1 :(得分:1)

要清理,这里是即将推出的React更新路径的简短描述。弃用警告将在下一个次要的React更新中推出,因此早在16.4中,弃用的方法将一直有效,直到下一个主要版本17更新。

我不建议在setState生命周期方法中执行componentDidUpdate,因为它会让你非常容易受到infite循环的攻击。<​​/ p>

我不太确定您尝试通过检查state是否已更改并且状态更改应始终由用户操作引起来实现的目标。当您调用setState tho时,您的组件将自动重新呈现。

为了清理事情,我会自己做这样的事情。您可以根据用户操作进行状态更改,并且在调用setState时,React组件将始终重新呈现。这是Reacts的本性。

如果我想传递数据,我会声明子组件并将数据作为道具传递。然后将它传递给子组件状态示例,在React 16.3 getDerivedStateFromProps -method中新引入,它返回普通对象并自动传递给组件状态。这个方法在初始渲染时调用,并且每次组件都接收到新的道具时也是如此,所以基本上每次当你的父组件状态发生变化时,都会在这个场景中调用。

如果您不希望子组件重新呈现,您也可以return null方法getDerivedStateFromProps

class MyComponent extends React.Component {
  // ES7 syntax, same as doing this in constructor
  // with, this.state = {}
  state = {
    value: false
  }

  handleClick = () => {
    /* Might as well write some logic here
     * and do setState at end
     */
    const { value } = this.state        

    /* and at end, well I just return value negated back */
    this.setState({
      value: !value
    })
  }

  render() {
    const { value } = this.state
    return (
      <div>
        {value ? 'im true' : 'im falsy'}
        <button onClick={this.handleClick} >Click me!</button>
        <SomeOtherComponent {...this.state} />
      </div>
    )
  }

}



class SomeOtherComponent extends React.Component {
  static getDerivedStateFromProps(nextProps, prevState) {
    if (nextProps.value) {
      return { text: 'it was true ' }
    }
    return { text: 'it was falsy' }
  }

  state = {
    text: null,
  }

  render() {
    return (
      <div>
        { this.state.text }
      </div>
    )
  }
}