【问题标题】:Why is my props updating before I update the state?为什么我的 props 在我更新状态之前就更新了?
【发布时间】:2019-06-10 22:06:04
【问题描述】:

我正在尝试更改 GrandChild 类 内的输入和 父类* 内的引导表。用户将更改 **GrandChild 类 中的输入,然后将其保存,因此可以在 父类 的引导表中看到更改;但是,在我调用 .onChange (这是我的保存)之前,我看到了这种奇怪的行为,我的道具正在发生变化。我相信这会导致我的输入无法正确保存或设置状态。

向下传递的数据:GrandParent => Parent => Child => GrandChild

发生在 Child 类的 handleSave() 函数中:

export class Child extends React.Component {
    constructor(props){
        this.state  = {
            data:this.props.data
        }
    }


    handleChange = (name, value) => {
        this.setState((prevState) => {
            let newState = {...prevState};
            newState.data.dataList[0][name] = value;  // data
            return newState;
        });
    };

    handleSave(){
        let dataList = this.state.data.dataList.slice();
        console.log("dataList state-dataList:", dataList);
        console.log("dataList before onChange 2:", this.props.data.dataList); //Same as dataList or this.state.data.dataList
        this.props.onChange("dataList", dataList);
        console.log("dataList onChange 3:", this.props.data.dataList); //Same as dataList or this.state.data.dataList
    }

    render() {
    return (
        <div>
            <GrandChild data={this.state.data} onChange={this.handleChange} />
        </div>
    )
}

子类的 this.props.onChange 被发送回 父类

export class Parent extends React.Component {
    constructor(props) {
        super(props);
        this.handleChange = this.handleChange.bind(this);
    }

    columns = [
      {dataField: '..', text: '...' }, 
      {dataField: '..', text: '...' },  
      {dataField: '..', text: '...' }, 
      {dataField: '..', text: '...'}];


    handleChange = (name, value) => {
        this.props.onChange(name, value);
    };

    render() {
        return (
            <div>
                <BootstrapTable
                    hover
                    condensed={true}
                    bootstrap4={true}
                    keyField={'id'}
                    data={this.props.data.dataList}
                    columns={this.columns}
                />
                <Child data={this.props.data} onChange={this.handleChange} />
            </div>


        );

    }

}

然后父类的 this.props.onChange* 被发送到 GrandParent 类

export class GrandParent extends React.Component {
constructor(props) {
    super(props);
    this.state = {
        data: {...this.props.location.state.data}
    };
    this.handleChange = this.handleChange.bind(this);
}   

    handleChange = (name, value) => {
        this.setState((prevState) => {
            let newState = {};
            let data = Object.assign({}, prevState.data);
            data[name] = value;
            newState.data = data;
            return newState;
        });
    };


render() {
return (
    <div>
        <Form>
        <Parent data={this.state.data} onChange={this.handleChange} />
        </Form>
    </div>
)
}

这是GrandChild的班级

export class GrandChild extends React.Component {
constructor(props) {
    super(props);
    this.handleInputChange = this.handleInputChange.bind(this);
}   

handleInputChange = (event) => {
    const target = event.target;
    const value = target.type === 'checkbox' ?
        target.checked :
        target.value;
    const name = target.name;
    this.props.onChange(name, value);
};


render() {
return (
    <div>
        <Form.Row>
            <Form.Group as={Col}>
                <Form.Label>Label Name</Form.Label>
                <Form.Control name="labelName" value={this.props.data.[0]labelName || ""} //ignore the index for now
                              onChange={this.handleInputChange}/>
            </Form.Group>
        </Form.Row>
    </div>
)
}
}

我预计 dataLists 的 console.logs() 会有所不同;但是,它们甚至在运行 this.props.onChange("dataList", dataList);

之前就给出了相同的对象

由于 setState 是异步的,第三个 dataList console.log 可能与状态 dataList 相同。

【问题讨论】:

    标签: reactjs react-state-management react-state


    【解决方案1】:

    看起来主要问题是你正在改变Child中的状态/道具:

        handleChange = (name, value) => {
            this.setState((prevState) => {
                // {...prevState} makes a shallow copy of `prevState`
                let newState = {...prevState};
                // Next you're modifying data deep in `newState`,
                // so it's mutating data in the `dataList` array,
                // which updates the source of truth for both props and state.
                newState.data.dataList[0][name] = value;
                return newState;
            });
        };
    

    一种方法(避免突变)是这样的:

    handleChange = (name, value) => {
      this.setState(prevState => ({
        data: {
          ...prevState.data,
          dataList: [
            {
              ...prevState.data.dataList[0],
              [name]: value
            },
            ...prevState.data.dataList.slice(1)
          ]
        }
      }));
    };
    

    如果这比您想要的更详细,您可以使用像 immutable-js 这样的库。

    另一个可能导致错误的问题是将道具复制到状态中。这篇文章给出了为什么不好的一些解释:https://overreacted.io/writing-resilient-components/#dont-stop-the-data-flow-in-rendering

    基本上:如果您在 state 中设置 props,然后更新 state 并将 props 传递给子项,那么您传递的数据将是陈旧的。看起来你在这里没有这样做,但很容易错过。避免这种情况的一种简单方法是将您计划设置的任何道具命名为状态initialProp 如果您的道具命名为initialData,那么很明显,从树中的那一点开始,您应该依赖状态中的值而不是道具。

    另外,Grandparent 中的handleChange 可以写得更简单:

        handleChange = (name, value) => {
          this.setState(prevState => ({
            data: {
              ...prevState.data,
              [name]: value
            }
          }))
        };
    

    【讨论】:

    • 感谢您的明确解释,是的,您的解决方案是正确的!我了解到我不能只更改数据中的数据。我也会确保花一些时间阅读文章。我知道我的问题将零作为唯一索引 data.dataList[0],如果有多个索引 data.dataList[i],我是否只需要更改 slice(1)?如果我正在编辑其他索引,我会看到问题。就像我尝试更改第一个索引然后更改第二个索引一样,第二个索引数据正在复制到第一个数据。但当然,我会接受你的答案作为接受的答案。
    • 能够用索引解决它:handleLineItemChange = (name, value) => { const newState = Object.assign({}, this.state); newState.data = Object.assign({}, newState.data); newState.data.dataList = newState.data.dataList.slice(); newState.data.dataList[i] = Object.assign({}, newState.data.dataList[i]); newState.data.dataList[i][name] = value; this.setState({ 数据: newState.data }); };没有你的指导是不可能做到的。谢谢!
    • 我很高兴它有帮助!
    猜你喜欢
    • 2021-06-04
    • 1970-01-01
    • 2023-01-28
    • 2017-01-25
    • 2011-04-23
    • 1970-01-01
    • 2020-04-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多