【问题标题】:componentWillReceiveProps not firing when the state gets updated for the first time第一次更新状态时,componentWillReceiveProps 不会触发
【发布时间】:2019-04-03 00:18:01
【问题描述】:

我有两个不相关的组件连接到 redux。一个是按钮,另一个是应用程序的主屏幕。计划是让 HomeScreen 知道何时单击该按钮。所以,我有一个动作和一个减速器来传递按钮的状态。这工作正常,只是当我第一次单击该按钮时 HomeScreen 没有收到更新。我必须单击按钮两次才能使状态通过。

添加事件操作:

import { PLUS_INCIDENT } from './types';

export const plusIncident = pressed => (dispatch) => {
  console.log('2: action: ', pressed);
  dispatch({
    type: PLUS_INCIDENT,
    payload: pressed
  });
};

按钮组件:

// The action
import { plusIncident } from '../redux/actions/plusIncident';

import { connect } from 'react-redux';

class AddIncidentButton extends Component {
  handleAddButtonPress = () => {
    const { pressed } = this.state;
    const { plusIncident } = this.props;

    const btnState = !pressed;
    this.setState({ pressed: btnState });
    plusIncident(btnState);
  };
...

}
...
export default connect(
  null,
  { plusIncident }
)(AddIncidentButton);

减速机:

import { PLUS_INCIDENT } from '../actions/types';

const initialiState = {
  pressed: false
};

function inc(state = initialiState, action) {
  switch (action.type) {
    case PLUS_INCIDENT:
      return {
        ...state,
        pressed: !action.payload
      };
    default:
      return state;
  }
}

主屏幕: componentWillReceiveProps 方法只有在点击按钮两次后才会被调用。

class HomeScreen extends React.Component {
  state = {
    pressed: false
  };

 componentWillReceiveProps(nextProps) {
    const { pressed } = this.props;
    if (pressed !== nextProps.pressed) {
      this.setState({ pressed: !nextProps.pressed });
    }
  }
...
}

const mapStateToProps = state => ({
  pressed: state.inc.pressed
});
export default connect(mapStateToProps)(HomeScreen);

【问题讨论】:

    标签: reactjs react-native react-redux


    【解决方案1】:

    尝试添加第一次调用的 componentDidMount()。收到更新后会调用componentWillRecieveProps:

    componentDidMount() {
          this.setState({ pressed: !this.props.pressed});
    }
    

    希望它有效..

    【讨论】:

    • 感谢您的回答。我没有尝试过,但它看起来很有希望。第三个答案对我有用。原来我在减速器中犯了一个错误。
    【解决方案2】:

    在你的减速器中

    import { PLUS_INCIDENT } from '../actions/types';
    
    const initialiState = {
      pressed: false
    };
    
    function inc(state = initialiState, action) {
      switch (action.type) {
        case PLUS_INCIDENT:
          return {
            ...state,
            pressed: !action.payload  // remove this and add action.payload
          };
        default:
          return state;
      }
    }
    

    删除 not(!) 运算符。

    希望对你有帮助

    【讨论】:

    • 感谢您的回答。有效。我还必须从主屏幕状态中删除“按下”并依赖道具。即直接使用 this.props.pressed。
    【解决方案3】:

    根据React docs,在初始挂载期间不会调用componentWillReceiveProps:

    React 在挂载期间不会使用初始道具调用 UNSAFE_componentWillReceiveProps()。只有当组件的某些 props 可能更新时,它才会调用此方法。

    无论如何,您都应该避免使用 componentWillReceiveProps,因为官方文档指出使用它通常会导致错误和不一致,并且在较新版本的 React 中已被弃用。


    另一方面,您完全错过了在您的方法中使用 Redux 的好处,因为您将 Redux 状态复制到已订阅 Redux 存储的 HomeScreen 组件内的内部状态。

    如果你需要根据pressed的值来渲染一些东西,像这样在render方法内部进行,组件会在每次pressed的值时重新渲染在调用一些 Redux 操作后更新:

    class HomeScreen extends React.Component {
    
        render() {
            const pressed = this.props.pressed;
    
            <div>
                {pressed ? 'button is pressed' : 'button is not pressed'}
            </div>
        }
    
    }
    
    
    
    const mapStateToProps = state => ({
      pressed: state.inc.pressed
    });
    export default connect(mapStateToProps)(HomeScreen);
    

    【讨论】:

    • 感谢您的回答。这不是我担心的初始状态。单击按钮后,我应该会收到第一个更新。请看下面的答案。
    • 知道了,很高兴你已经解决了。有了这个,我仍然建议避免状态重复。
    猜你喜欢
    • 1970-01-01
    • 2019-07-03
    • 1970-01-01
    • 2021-07-03
    • 2020-11-08
    • 2023-01-26
    • 2015-04-08
    • 1970-01-01
    • 2019-05-07
    相关资源
    最近更新 更多