ReactJS setState конфликтует с getDerivedStateFromProps - PullRequest
0 голосов
/ 05 июня 2018

Я пытаюсь следовать шаблону проектирования в https://github.com/reactjs/rfcs/issues/26 (см. Ответы bvaughn) и создать редактируемую форму ReactJS, которая читает данные с сервера, отображает их в полях формы и позволяет использовать для редактирования значений.а затем сохранить эти данные обратно в базу данных.

У меня есть некоторый необходимый код:

const mapStateToProps = state => {
    return {
        invoice: state.invoice,
        invoiceReady: state.invoiceReady,
    };
};

 static getDerivedStateFromProps(nextProps, prevState) {
        if (nextProps.match.params.id !== prevState.id) {
            return update(
                prevState, {
                    ['id']: {$set: nextProps.match.params.id},
                    ['invoiceReady']: {$set: false}
                });
        } else {
            return update(
                prevState, {
                    ['invoice']: {$set: nextProps.invoice},
                    ['invoiceReady']: {$set: nextProps.invoiceReady}
                });
        }
    }

 handleChange(event) {
        const state = update(
            this.state, {
                invoice: {
                    [event.target.id]: {$set: event.target.value}
                }
            }
        );
        this.setState(state);
    }

componentDidMount() {
        this.requestInvoice();
    }

componentDidUpdate(prevProps, prevState) {
        if (!this.state.invoiceReady) {
            this.requestInvoice();
        }
    }

, и мой JSX-код содержит редактируемые поля, такие как:

                        <input
                            type="text"
                            className="form-control"
                            id="invoiceDate"
                            value={this.state.invoice.invoiceDate}
                            onChange={this.handleChange}
                        />

Итак, согласно указанному шаблону я инициируюзапрос к серверу с помощью requestInvoice, некоторые другие компоненты обрабатывают это действие, получают и сохраняют счет-фактуру в хранилище Redux, поэтому эти данные автоматически записываются в переменную props.invoice, и я в дальнейшем пишу props.invoice в this.state.invoice на getDerivedStateFromProps для дальнейшей локальной обработки данных счета.При работе с формой вызываются события handleChange и с помощью immutability-helper (функция обновления) обновленные поля записываются в новое состояние и вызывается setState.

Моя проблема в том, что во время вызова setState React вызывает getDerivedStateFromProps, и поэтому props.invoice перезаписывает любые изменения, поступающие от пользователя и обрабатываемые в функции handleChange:setState.

Итак - как решить эту проблему: конфликт между setState и getDerivedStateFromProps?

Возможны несколько вариантов:

  • myдизайн может быть ошибочным.Например, может быть, я не должен пытаться переместить props.invoice в this.state.invoice (почему бы и нет?)?Но с другой стороны было бы неплохо сохранить счет в this.state и быть уверенным, что все изменения применяются к this.state.invoice во время редактирования счета.
  • mybe, я должен предотвратить выполнение getDerivedStateFromProps во время setState?

Может быть, какой-то другой шаблон или код дизайна больше подходит для моей формы ReactJS?

Я использую ReactJ 16.x

Ответы [ 2 ]

0 голосов
/ 07 июня 2018

Я пришел к следующему решению - с помощью переменной this.state.stateUpdate - и считаю это ответом на мой вопрос (пожалуйста, прокомментируйте, если это не правильное и опрятное решение, я могу принять и другой ответ, есличто работает):

 const mapStateToProps = state => {
        return {
            invoice: state.invoice,
            invoiceReady: state.invoiceReady,
            stateUpdate: false 
        };
    };

     static getDerivedStateFromProps(nextProps, prevState) {
            if (prevState.stateUpdate) {
              return update(
                prevState, {
                    stateUpdate: {$set: false}
                }
              )
            }
            if (nextProps.match.params.id !== prevState.id) {
                return update(
                    prevState, {
                        ['id']: {$set: nextProps.match.params.id},
                        ['invoiceReady']: {$set: false}
                    });
            } else {
                return update(
                    prevState, {
                        ['invoice']: {$set: nextProps.invoice},
                        ['invoiceReady']: {$set: nextProps.invoiceReady}
                    });
            }
        }

     handleChange(event) {
            const state = update(
                this.state, {
                    invoice: {
                        [event.target.id]: {$set: event.target.value}
                    },
                    stateUpdate: {$set: true}
                }
            );
            this.setState(state);
        }

    componentDidMount() {
            this.requestInvoice();
        }

    componentDidUpdate(prevProps, prevState) {
            if (!this.state.invoiceReady) {
                this.requestInvoice();
            }
        }
0 голосов
/ 05 июня 2018

Если вы решили использовать react-redux for component state management, тогда вы должны avoid управлять этим component internal state, используя setState, как его контролирует redux store.

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

с учетом вашего сценария, во время handleChange вместо вызова setState, лучше на dispatch и action на update the state in redux store, а затем через connect он будет отражаться на вашем компоненте так же, как вы вызываете API.

handleChange(event) {
        const stateData = invoice: {
                    [event.target.id]: {$set: event.target.value}
                }; 
        this.props.callDispatch({'UPDATE_SOME_DATA',stateData})
    }

Необходимо только позаботиться только о том, чтобы reducers обновлял только требуемые переданные данные свойств и оставлял другие данные без изменений, обновляемые APIdispatch action процесс.

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