【问题标题】:ReactJS setState conflicts with getDerivedStateFromPropsReactJS setState 与 getDerivedStateFromProps 冲突
【发布时间】:2018-06-05 15:00:48
【问题描述】:

我正在尝试遵循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 函数中。

那么 - 如何解决这个问题:setStategetDerivedStateFromProps 之间的冲突?

几个选项可能是:

  • 我的设计可能有缺陷。例如。也许我不应该尝试将props.invoice 移动到this.state.invoice(为什么不呢?)?但另一方面,最好将发票保存到 this.state 中,并确保在编辑发票期间将所有更改应用到 this.state.invoice
  • 我应该阻止getDerivedStateFromPropssetState 期间执行吗?

也许其他一些设计模式或代码更适合我的 ReactJS 表单?

我正在使用 ReactJ 16.x

【问题讨论】:

    标签: reactjs react-redux


    【解决方案1】:

    如果您决定使用react-redux for component state management,那么您应该avoid 使用setState 来管理component internal state,因为它由redux store. 控制

    否则会导致这样的问题,你可能需要处理很多 if-else。

    考虑到您的情况, 在handleChange 期间,而不是调用setState,最好是dispatchactionupdate 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 仅更新所需传递的属性数据,并保持 API dispatch action 进程更新的其他数据完好无损。

    【讨论】:

    • 是的,我知道解决方案,我应该将所有状态保留在 Redux 存储中。但是目前我不想将业务对象保存在 Redux 商店中,我想从商店中获取它,但我想保留在本地 this.state 中以进行进一步操作,并且我想将我的对象提交给 Redux仅当用户完成对对象的工作时才存储。如果一个 React 组件在其 this.state 中我想在用户使用它时暂时保留我的对象,则整个业务对象形式。
    【解决方案2】:

    我已经得出以下解决方案 - 在 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();
                }
            }
    

    【讨论】:

      猜你喜欢
      • 2020-12-23
      • 1970-01-01
      • 1970-01-01
      • 2018-12-03
      • 1970-01-01
      • 2013-04-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多