简体   繁体   English

状态突变作为副作用?

[英]State was mutated as a side effect?

I ran into a weird problem with my code.我的代码遇到了一个奇怪的问题。 Sorry if this is already asked, I wanted to search for the reason but I don't even know how to phrase the problem.对不起,如果这已经被问到,我想搜索原因,但我什至不知道如何表述这个问题。

Essentially, I have a code similar to this:本质上,我有一个与此类似的代码:

class Component extends Component {
constructor(props) {
    super(props);
    this.state = { grid: [["", "", "", ""]], base: ["", "", "", ""]};
}

csvParse = (row, column) => e => {
    const newData = Papa.parse(e.target.value).data.filter(
        x => x.length !== 1 && x[0] !== ""
    );
    //newData will result in a 2D array such as [["1", "2", "3", "4"], ["5", "6", "7", "8"], ["9", "10", "11", "12"]]
    //newData is receiving the data from a copy and paste from a CSV file

    const { base } = this.state;
    let grid = this.state.grid

    for (let i = row; i < newData.length + row; i++) {
        for (let j = column; j < 4; j++) {
            try {
                grid[i][j] = newData[i][j];//1
            } catch (err) {
                grid.push(base);//2
                grid[i][j] = newData[i][j];//3 One of these is causing it, I don't know which
            }
        }
    }

    this.setState({grid},()=>{
        console.log(this.state.base) 
    //Actually logs ["9", "10", "11", "12"] instead of ["", "", "", ""]. Why was it mutated?
    })
};

render() {
    //The component renders a 4 X 1 grid of textareas. The number of rows will increase based on this.state.grid. Doesn't seem like its the issue.
    return (
        <Fragment>
            <Grid container>
                    {this.state.grid.map((row, rowIndex) => (
                        <Fragment key={rowIndex}>
                            <Grid item xs={3}>
                                <textarea
                                    onChange={this.csvParse(rowIndex, 0)}
                                    value={row[0]}
                                />
                            </Grid>
                            <Grid  item xs={3}>
                                <textarea
                                    onChange={this.csvParse(rowIndex, 1)}
                                    value={row[1]}
                                />
                            </Grid>
                            <Grid item xs={3}>
                                <textarea
                                    onChange={this.csvParse(rowIndex, 2)}
                                    value={row[2]}
                                />
                            </Grid>
                            <Grid item xs={3}>
                                <textarea
                                    onChange={this.csvParse(rowIndex, 3)}
                                    value={row[3]}
                                />
                            </Grid>
                        </Fragment>
                    ))}
                </Grid>
        </Fragment>
    );
}

} }

Every time I ran it this.state.base would change to something else, like [""].每次我运行它时 this.state.base 都会变成别的东西,比如 [""]。 This code has no problem if I ran it without this.state.base如果我在没有 this.state.base 的情况下运行它,此代码没有问题

Ah, I believe you want state.base to remain ['','','',''] .啊,我相信你希望state.base保持['','','',''] If that's the case read on.如果是这种情况,请继续阅读。 Else let me know and we can iterate.否则让我知道,我们可以迭代。

To understand what's changing state.base you need to understand the difference between pass by reference and pass by value.要了解state.base发生了什么变化,您需要了解按引用传递和按值传递之间的区别。

Pass-by-reference vs. Pass-by-value引用传递与值传递

Essentially in pass by reference, if you create a variable a , then create a variable b equal to a , then change the value of a key/value in a , you'll also change b :基本上在按引用传递,如果你创建一个变量a ,然后创建一个变量b等于a ,然后更改键/值的值a ,您还可以改变b

var a = {'hi': 'mom'}
var b = a;
a['hi'] = 'world';
console.log(b);
// logs {hi: 'world'}

In pass by value, if you create a variable a , then create a variable b equal to a , then change the value of a , you won't change b :在按值传递,如果你创建一个变量a ,然后创建一个变量b等于a ,然后更改的值a ,你都不会改变b

var a = true;
var b = a;
a = false;
console.log(b);
// logs true;

Objects {} and Arrays [] are pass by reference in JavaScript, most other primitive data types are pass by value.对象{}和数组[]在 JavaScript 中是按引用传递的,大多数其他原始数据类型是按值传递。 This is a strange but critically important facet of the language itself, and it changes the way we need to write React.这是语言本身一个奇怪但至关重要的方面,它改变了我们编写 React 的方式。

How this applies to your case这如何适用于您的案例

In your case, you assign your state.base to base , then you add base to grid , then you mutate grid .在您的情况下,您将state.base分配给base ,然后将base添加到grid ,然后更改grid It's only a matter of time before state.base gets mutated. state.base发生变异只是时间问题。

To avoid this, just change:为避免这种情况,只需更改:

grid.push(base);

to:到:

grid.push(Object.assign([], base));

Object assign here will create a new variable with the value of base, and add that to grid.此处的对象分配将创建一个值为base 的新变量,并将其添加到网格中。 That prevents any changes to grid from modifying state.base .这可以防止对grid任何更改修改state.base

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM