componentWillReceiveProps не запускается при первом обновлении состояния

#reactjs #react-native #react-redux

#reactjs #react-native #реагировать-redux

Вопрос:

У меня есть два несвязанных компонента, подключенных к redux. Один из них — кнопка, а другой — рабочий стол приложения. План состоит в том, чтобы сообщить рабочему столу, когда нажата кнопка. Итак, у меня есть действие и редуктор для передачи статуса кнопки. Это работает нормально, за исключением того, что рабочий стол не получает обновления, когда я нажимаю кнопку в первый раз. Я должен дважды нажать кнопку, чтобы состояние завершилось.

Добавить действие инцидента:

 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);
  

Ответ №1:

Попробуйте добавить componentDidMount(), который также будет вызываться в первый раз. componentWillReceiveProps будет вызван после получения обновления:

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

Надеюсь, это сработает..

Комментарии:

1. Спасибо за ответ. Я не пробовал это, но это выглядит многообещающе. Третий ответ сработал для меня. Оказывается, я допустил ошибку в редукторе.

Ответ №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(!).

Надеюсь, это поможет

Комментарии:

1. Спасибо за ответ. Это сработало. Мне также пришлось удалить ‘pressed’ из состояния рабочего стола и вместо этого полагаться на props. т. Е. использовать this.props.pressed напрямую.

Ответ №3:

Согласно документам React, componentWillReceiveProps не будет вызываться во время первоначального монтирования:

React не вызывает UNSAFE_componentWillReceiveProps() с начальными реквизитами во время монтирования. Этот метод вызывается только в том случае, если некоторые реквизиты компонента могут обновиться.

В любом случае вам следует избегать использования componentWillReceiveProps, поскольку в официальной документации указано, что его использование часто приводит к ошибкам и несоответствиям, и он устарел в более новых версиях React.


С другой стороны, вы полностью упускаете преимущества использования Redux в вашем подходе, поскольку вы копируете состояние Redux в свое внутреннее состояние внутри компонента рабочего стола, который уже подписан на Redux store.

Если вам нужно отобразить что-либо на основе значения нажатой, сделайте это внутри метода визуализации следующим образом, и компонент будет повторно отображать каждый раз, когда значение нажатой обновляется после вызова некоторого действия 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);
  

Комментарии:

1. Спасибо за ответ. Это не начальное состояние, о котором я беспокоюсь. После нажатия кнопки я должен получить это первое обновление. Пожалуйста, смотрите ответ под этим.

2. Понял, рад, что вы разобрались с этим. При этом я по-прежнему рекомендую избегать дублирования состояния.