Обновить обзорную сцену после изменения состояния в другой сцене с помощью react/redux/react-native-router-flex

Самый упрощенный рабочий пример представлен на github!!!

У меня есть простое приложение, чтобы научиться создавать приложения с помощью React Native и Redux. Насколько я понимаю, если вы отображаете данные из состояния избыточности в своем методе рендеринга, а затем значения этого состояния изменяются, тогда значение также будет изменено, и реакция повторно отображает все компоненты, которые необходимо повторно визуализировать из-за изменения состояния.

Приложение доступно на github: https://github.com/schingeldi/checklist

Это действительно просто. У меня есть обзор, если вы нажмете на статус записи, вы попадете на подробную страницу. Если вы нажмете «Отметить xxx», статус изменится в состоянии редукции (согласно журналам), но не обновится в обзорной сцене.

В основном у меня есть Обзор.js:

class Overview extends Component {

    constructor(props) {
        super(props);
        this.state = {fetching:false};
    }

    entries() {
        // console.log("Overview");
        // console.log(this.props);
        // console.log(this.props.entries);


        return Object.keys(this.props.entries).map(key => this.props.entries[key]);
    }

    componentDidMount() {
        this.setState({fetching:true});
        this.props.actions.getEntries()
            .then( (res) => {
                this.setState({fetching: false});
            })
    }

    handleChange(entryId) {
        Actions.detail({id: entryId});
    }


    render() {

        return (
        <View>
            <ScrollView>
                { !this.state.fetching &&  this.entries().map((entry) => {

                    return (
                        <TouchableHighlight key={entry.id}>
                        <View  >
                            <Text>{entry.name}</Text>
                            <TouchableHighlight onPress={(entryId ) => this.handleChange(entry.id)}><Text>{entry.status}</Text></TouchableHighlight>
                            <Text>---------------------------</Text>

                        </View>
                        </TouchableHighlight>
                    )
                    }

                    )
                }
                {this.state.fetching ? <Text>Searching </Text> : null }
            </ScrollView>


        </View>
    )}
}

function mapStateToProps(state) {

    return {entries: state.default.entries };
}

function mapDispatchToProps(dispatch) {
    return {actions: bindActionCreators(actions,dispatch)};
}

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

При нажатии на статус ( {entry.status} ) я открываю другую сцену Details.js:

class Detail extends Component {

    constructor(props) {
        super(props);
        this.state = {}
    }

    componentWillMount() {
        this.setState({
            entry: this.props.entries[this.props.id]
        })
    }

    patchEntry(newStatus) {
        console.log("Details: patchEntry with " + this.props.id +" and " + newStatus );
        this.props.actions.patchEntry(this.props.id, newStatus);
    }

    render() {
        return (
            <View>
                <Text>{this.state.entry.name}</Text>

                <TouchableHighlight onPress={() => this.patchEntry('done')}><Text>Mark done</Text></TouchableHighlight>
                <TouchableHighlight onPress={() => this.patchEntry('cancelled')}><Text>Mark cancelled</Text></TouchableHighlight>
            </View>
        )
    }
}



function mapStateToProps(state) {
    console.log(state);
    return {entries: state.default.entries };
}


function mapDispatchToProps(dispatch) {
    return {actions: bindActionCreators(actions,dispatch)};
}

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

И у меня есть действие и редьюсер, которые вызываются отлично, когда нажимается один из TouchableHighlights. Я даже вижу в логах, что состояние меняется при выводе всего состояния.

Но мой вопрос в том, как мне обновить статус на сцене обзора, как только я вернусь (всплываю) из сцены деталей?

Если вам нужна дополнительная информация, дайте мне знать, но ее должно быть просто воспроизвести, поскольку я написал целое рабочее приложение. Просто клонируйте, установите npm и запустите его.

Большое спасибо за твою помощь.


person schingeldi    schedule 26.06.2017    source источник


Ответы (1)


Я быстро просмотрел ваш код, и вот несколько предложений/информации.

В файле Detail.js вы устанавливаете свое состояние после монтирования компонента. Когда вы обновляете свой магазин избыточности и получаете обновленные реквизиты, он не будет обновлять ваш пользовательский интерфейс, потому что он отражает ваше состояние, и ваше состояние не получит новое значение, потому что вы устанавливаете его только для метода componentWillMount. Дополнительную информацию см. здесь, в документации.

Также кажется, что вам не очень понятно, когда использовать состояние компонента React. В этом примере из файла Detail.js вам вообще не нужно состояние компонента. Вы можете вычислить это значение непосредственно из свойств.

Ex:

render() {
  const entry = this.props.entries[this.props.id];
  return (
    <View>
      <Text>{entry.name}</Text>

      <TouchableHighlight onPress={() => this.patchEntry('done')}><Text>Mark done</Text></TouchableHighlight>
      <TouchableHighlight onPress={() => this.patchEntry('cancelled')}><Text>Mark cancelled</Text></TouchableHighlight>
    </View>
  )
}

Вы даже можете сделать это внутри своей функции mapStateToProps. Подробнее здесь.

Ex:

function mapStateToProps(state, ownProps) {
  return {
    entries: state.default.entries,
    entry: state.default.entries[ownProps.id],
  };
}

Похоже, ваш файл Overview.js в порядке с обновляемым пользовательским интерфейсом, потому что его метод рендеринга отражает props, а не его состояние.

ОБНОВЛЕНИЕ 27.06

Я только что проверил ваш reducers, и, возможно, у вас тоже есть что исправить.

case ENTRY_PATCHING:
  let patchedEntries = state.entries;
  patchedEntries[action.data.entryId].status = action.data.newStatus;

  return {...state,
    entries: patchedEntries
  }

В этом редукторе вы мутируете свое состояние, и вы не должны этого делать. Магазин избыточности не может быть изменен. Подробнее об этом можно узнать здесь http://redux.js.org/docs/recipes/reducers/ImmutableUpdatePatterns.html

Итак, пример исправления:

case ENTRY_PATCHING:
  const patchedEntry = {
    ...state.entries[action.data.entryId],
    status: action.data.newStatus
  }

  return {
    ...state,
    entries: {
      ...state.entries,
      [action.data.entryId]: patchedEntry,
    }
  }
person André Junges    schedule 26.06.2017
comment
Спасибо Андре за ваш ответ. Я попробую это, как только у меня будет немного времени сегодня вечером. - person schingeldi; 27.06.2017
comment
Привет Андре. Я попробовал ваше предложение, и вы правы, мне не нужен componentWillMount в Detail.js Но, тем не менее, как вы упомянули, что мой Review.js в порядке, почему он не обновляется, когда я изменяю состояние редукции в Detail.js . Я ожидаю, что при использовании кнопки «Назад» для возврата к обзору обзор будет перерисован с новым состоянием. Это не так. У вас есть идеи, почему? - person schingeldi; 28.06.2017
comment
@schingeldi Я обновил ответ. Загляните в новые заметки. - person André Junges; 28.06.2017
comment
Привет, большое спасибо за ваши ответы. Я тоже это понял, сделал что-то подобное и исправил проблему. Я сравню ваш подход со своим, но, конечно, проблема была в редукторе. Большое спасибо - person schingeldi; 28.06.2017