Реагировать на натуру, не обновляя компонент - PullRequest
0 голосов
/ 10 января 2019

Я пытаюсь настроить redux с помощью собственного ответа, но он не обновляет мои компоненты при обновлении магазина.

class Dinner extends React.Component {

    componentDidUpdate() {
        console.log('does not get called when store update');
    }

    setSelected = (meal) => {
        var index = this.props.selectedDinner.indexOf(meal);

        if (index === -1) {
            console.log('Adding meal to selected: '+meal.name);
            if (this.props.selectedDinner[0] === null) {
                var tempArr = this.props.selectedDinner;
                tempArr[0] = meal;
                this.props.setSelectedDinner(tempArr);

            } else if(this.props.selectedDinner[1] === null)  {
                var tempArr = this.props.selectedDinner;
                tempArr[1] = meal;
                this.props.setSelectedDinner(tempArr);
            } else if(this.props.selectedDinner[2] === null)  {
                var tempArr = this.props.selectedDinner;
                tempArr[2] = meal;
                this.props.setSelectedDinner(tempArr);
            }
        } else {
            console.log("removing meal from selected: "+meal.name)
            var tempArr = this.props.selectedDinner;
            tempArr[index] = null;
            this.props.setSelectedDinner(tempArr);
        }
        LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
        this.forceUpdate()
    };

    render() {
        return (
          <View style={{flex: 1, width: 360, justifyContent: 'center', alignItems: 'center', paddingBottom: 20}}>
            <View style={{width: 340, backgroundColor: 'white', justifyContent: 'flex-start', alignItems: 'center'}}>
              <Text style={{height: 50, fontSize: 20, fontWeight: 'bold', flex: 1, justifyContent: 'center', alignItems: 'center'}}>Dinner</Text>
              {
                this.props.dinnerFeed.map((prop, key) => 
                  prop === null ?
                    <TouchableOpacity style={{width: 320, height: 120, backgroundColor: 'lightgrey', flex: 1, justifyContent: 'center', alignItems: 'center', zIndex: 1, marginBottom: 10, flexShrink: 0}} key={key}><LoadingMealTile /></TouchableOpacity>
                    :
                    (prop === 'none' ? 
                      <TouchableOpacity style={{width: 320, height: 120, backgroundColor: 'lightgrey', flex: 1, justifyContent: 'center', alignItems: 'center', zIndex: 1, marginBottom: 10, flexShrink: 0}} key={key}><BlankMealTile /></TouchableOpacity>
                      :
                      this.props.selectedDinner === null || this.props.selectedDinner.indexOf(prop) === null ?
                        <TouchableOpacity onPress={this.setSelected.bind(this, prop)} style={{width: 320, height: 120, backgroundColor: 'lightgrey', flex: 1, justifyContent: 'center', alignItems: 'center', zIndex: 1, marginBottom: 10, flexShrink: 0}} key={key}><MealTile selected={-1} name={prop.name} id={prop.id} url={prop.url} key={key}/></TouchableOpacity>
                        :
                        <TouchableOpacity onPress={this.setSelected.bind(this, prop)} style={{width: 320, height: 120, backgroundColor: 'lightgrey', flex: 1, justifyContent: 'center', alignItems: 'center', zIndex: 1, marginBottom: 10, flexShrink: 0}} key={key}><MealTile selected={this.props.selectedDinner.indexOf(prop)} name={prop.name} id={prop.id} url={prop.url} key={key}/></TouchableOpacity>
                    )
                )  
              }

              <TouchableOpacity onPress={this.props.loadFeedMeals} style={{width: 320, height: 50, backgroundColor: 'lightgrey', flex: 1, justifyContent: 'center', alignItems: 'center', zIndex: 1, marginBottom: 10}}><Text style={{fontSize: 15, }}>Load More Meals</Text></TouchableOpacity>
            </View>
          </View>
        );
      }
    }


    function mapStateToProps(state) { 
      return {
           dinnerFeed: state.dinnerFeed,
           selectedDinner: state.selectedDinner,
      }
    };

    function mapDispatchToProps(dispatch) {
      return {
        setDinnerMeals: (dinnerMeals) => dispatch(setDinnerMeals(dinnerMeals)),
        setSelectedDinner: (selectedDinner) => dispatch(setSelectedDinner(selectedDinner)),

      }
    };

    export default connect(mapStateToProps, mapDispatchToProps)(Dinner);

Функция setSelectedDinner корректно изменяет хранилище редуксов, но компонент не вызывает свою функцию componentDidUpdate

edit: вот код редуктора


    export default (state, action) => {
        console.log(action);
        switch (action.type) {
            case "SET-SELECTED-DINNER":
                return {
                        ...state,
                        selectedDinner: action.selectedDinner
                  };
            default:
                return state;
        }
    };

Я полагаю, что этот код не должен изменять состояние напрямую, потому что я использовал этот редуктор для приращения в проектеactjs

Ответы [ 2 ]

0 голосов
/ 10 января 2019

Самая распространенная причина обновления состояния Redux, но не обновляемых подключенных компонентов, - это изменение состояния внутри редуктора. Очень похожая общая проблема - это не признание того, что Redux connect HoC выполняет поверхностное сравнение.

Это потому, что Redux проверяет изменения, используя равенство объектов. (если сравнение === возвращает true, объект считается не измененным.)

Рассмотрим следующее неверное редуктор:

function todoApp(state = initialState, action) {
  switch (action.type) {
    case SET_VISIBILITY_FILTER:
      return state.visibilityFilter = action.filter;
    default:
      return state
  }
} 

Поскольку вышеприведенный редуктор изменяет состояние, обновление не запускается.

Правильный пример (взятый из Redux документации ) показан ниже:

function todoApp(state = initialState, action) {
  switch (action.type) {
    case SET_VISIBILITY_FILTER:
      return Object.assign({}, state, {
        visibilityFilter: action.filter
      })
    default:
      return state
  }
} 

Неглубокое сравнение

Так же, как и вышеупомянутая лучшая практика не изменять состояние, а всегда возвращать новое состояние для всего, что меняется, важно помнить, что Redux connect использует это поверхностное сравнение для всех объектов, возвращаемых mapStateToProps.

Рассмотрим упрощенную версию вашей mapStateToProps функции:

function mapStateToProps(state) { 
    return {
        selectedDinner: state.selectedDinner,
    }
};

А теперь подумайте, как вы передаете выбранный ужин своему действию setSelectedDinner (снова упрощенно):

setSelected = (meal) => {
    var index = this.props.selectedDinner.indexOf(meal);

    // when index === -1 we need to add this meal
    if (index === -1) {     
        // there is no meal at index 0 so we add it                    
        if (this.props.selectedDinner[0] === null) {
            // NOTICE - the line below still references selected dinner in state!
            var tempArr = this.props.selectedDinner;
            tempArr[0] = meal;

            // NOTICE - we are calling setSelectedDinner with the same object
            // that comes from state! 
            this.props.setSelectedDinner(tempArr);
        }
    }
}

Итак, проблема в том, что в вашей функции редуктора вы просто заменяете выбранный объектDinner самим собой, поэтому Redux не видит обновлений.

Самое быстрое изменение, которое решит вашу проблему - это изменить функцию редуктора для чтения (вызов слайса клонирует ваш массив):

export default (state, action) => {
    switch (action.type) {
        case "SET-SELECTED-DINNER":
            return {
                    ...state,
                    selectedDinner: action.selectedDinner.slice()
              };
        default:
            return state;
    }
};

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

  1. Переместите логику, которая изменяет ваш массив selectedDinner, из компонента и поместите его в редуктор.

  2. Ввести селекторы

0 голосов
/ 10 января 2019

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...