簡體   English   中英

避免在 map() 中通過 Object.assign() 進行狀態突變

[英]Avoid state mutation by Object.assign() inside map()

在 componentDidMount 我這樣做了:

     apps.forEach(app => {
            if (chosenAppId) {
                if (app.id === chosenAppId) {
                    this.setState({ map: this.props.map });
                }
            }
        });

現在,當我在某些功能中執行此操作時:

 this.setState({
            ...this.state.map,
            areas: this.state.map.areas.map(el =>
                el._id === area._id
                    ? Object.assign(el, {
                          chooseDevice: false,
                          editModal: true
                      })
                    : Object.assign(el, { chooseDevice: false })
            )
        });

我有持久的 redux 狀態,在這種情況下,我希望在重新加載 this.state.map === this.props.map 但不知何故這個 object.assign 改變了我的 redux 狀態,並且在重新加載時所有都被保存到 reducer。

我縮小了范圍,它與 object.assign 有關系,因為如果我將 .concat() 與 this.state.map 相關聯,則不會更改 redux 狀態。

如何? 我真的不明白。 沒有調度 redux action,不知道這是怎么發生的。

Object.assign(el, { chooseDevice: false })將改變el

看起來你從 props(因此很可能是 Redux 商店)復制到 state 中。 因此,它與 Redux 存儲中已經存在的對象引用相同,因此您正在改變存儲中的值。

請注意,我們的官方 Redux Toolkit 包默認包含一個突變檢測中間件,當您不小心改變值時會拋出錯誤。

您對問題的根本原因是完全正確的 - Object.assign()正在改變您在map()中引用的原始數組項。

要解決這個問題,只需擺脫Object.assign()改變您的狀態:

 this.setState({
    ...this.state.map,
    areas: this.state.map.areas.map(el => ({
       ...el,
       chooseDevice: false,
       ...(el._id === area.id && {editModal: true})
    }))
 });

當您傳播一個對象時,它不會克隆現有屬性,它只是將它們復制到新對象中,這意味着實例屬性將保留,例如

 const obj = { numbers: [1, 2, 3], person: { name: 'Foo' } } const copy = { ...obj }; copy.numbers.push(4); copy.person.name = 'Bar' console.log(obj.numbers) // [1,2,3,4] console.log(obj.person) // { name: 'Bar' } console.log(copy.numbers) // [1,2,3,4] console.log(copy.person) // { name: 'Bar' }

注意原始對象是如何通過對副本的更改而更新的

因此,當您將狀態擴展到本地狀態時,即

 ...this.state.map

然后在實例屬性上使用Object.assign ,您在不經意間同時更新了 Redux 狀態。

使用 Object.assign()

Object.assign()方法將所有可枚舉的自身屬性從一個或多個對象復制到目標對象。

Object.assign(target, ...sources)

目標

目標對象 - 應用源屬性的對象,修改后返回。

來源

源對象 — 包含您要應用的屬性的對象。

Object.assign() - JavaScript | MDN

如果您不希望更改提供的元素,請定位一個空對象。 這樣el和第三個參數中的附加數據將被分配給一個新對象,而不是覆蓋el屬性。

this.setState(prevState => ({
    ...prevState.map,
    areas: prevState.map.areas.map(el =>
        el._id === area._id
            ? Object.assign({}, el, {
                  chooseDevice: false,
                  editModal: true
              })
            : Object.assign({}, el, { chooseDevice: false })
    )
}));

有對象傳播(緊湊型)

如果你想讓 ir 更緊湊,你也可以把它變成一個對象傳播,並使用內聯 if 來改變editModal的條件。

this.setState(prevState => ({
    ...prevState.map,
    areas: prevState.map.areas.map(el => ({
        ...el,
        chooseDevice: false,
        editModal: el._id === area._id ? true : el.editModal
    }))
}));

編輯: this.state不應在setState

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM