簡體   English   中英

為什么我的 globalState state object 在我自己更新之前被更新?

[英]Why is my globalState state object being updated before I update it myself?

我有一個多選項卡視圖,我通過全局 state 控制數據,並通過 useContext(以及 setState 更新程序函數)傳遞。

結構類似於

globalState: {
    company: {
        list: [
            [{name: ..., ...}, {field1: ..., ... }],
            [{name: ..., ...}, {field1: ..., ... }],
            ...
        ]
    },
    ...
}

我在第一個選項卡中有一個表格,其中每一行顯示每個內部列表數組( globalState.company.list[X][0] )的第一個 object 中的詳細信息,並且有幾個復選框來切換第二個中的字段每個內部列表數組 ( globalState.company.list[X][1] ) 中的 object。

我遇到的問題是,當我檢查特定字段的復選框時,所有公司都將該字段設置為該值,然后我在復選框本身的onChange調用中調用setGlobalState(...)

以下是創建復選框和處理程序流程的所有相關代碼:

<td><Checkbox
    disabled={tpr.disabled} // true or false
    checked={tpr.checked} // true or false
    onChange={checkboxOnChange} // function handler
    targetId={company.id} // number
    field={"field1"} />
</td>

復選框定義

const Checkbox = React.memo(({ disabled, checked, onChange, targetId, field }) => {
    return (
        <input
            type="checkbox"
            style={ /* omitted */ }
            defaultChecked={checked}
            disabled={disabled}
            onChange={(e) => onChange(e, targetId, field)}
        />
    );
});

onChange 處理程序回調

const checkboxOnChange = (e, id, field) => {
    const checked = e.target.checked;

    console.log("GLOBAL STATE PRE", globalState.companies.list);

    let foundCompany = globalState.companies.list.find(company => company[0].id === id);
    foundCompany[1][field].checked = checked;
    console.log("foundCompany", foundCompany);

    console.log("GLOBAL STATE POST", globalState.companies.list);

    setGlobalState(prevState => ({
        ...prevState,
        companies: {
            ...prevState.companies,
            list: prevState.companies.list.map(company => {
                console.log("company PRE ANYTHING", company);
                if (company[0].id === foundCompany[0].id) {
                    console.log("Inside here");
                    return foundCompany;
                }
                console.log("company", company);
                return company;
            })
        }
    }));
};

我從GLOBAL STATE PRE日志中看到,如果我要選中 field1 的框,那么在我修改其他任何內容之前,所有公司都會先選中 field1。 我可以確認,在選中該框之前,globalState 與我期望的一樣,所有數據和字段在加載時都正確設置。

在下圖中,我在第二家公司數組中選中了 TPR 框,在發生任何其他事情之前,第二家和第三家公司已經將 TPR 設置為 true。

顯示 GLOBAL STATE PRE 日志消息的瀏覽器控制台

任何幫助將不勝感激,我將分享我能夠分享的更多細節。 謝謝你。

只是不要直接改變 state object :

const checkboxOnChange = (e, id, field) => {
    const checked = e.target.checked;
    setGlobalState(prevState => ({
        ...prevState,
        companies: {
            ...prevState.companies,
            list: prevState.companies.list.map(company => {
                if (company[0].id === id) {
                    return {
                        ...company,
                        checked
                    };
                }
                return {
                    ...company
                };
            })
        }
    }));
};  

globalState object 在您調用 setGlobalState 之前正在更新,因為您正在改變當前的 state(例如foundCompany[1][field].checked = checked;

解決此問題的一種方法是復制 state object,使其不引用當前的 state。 例如

var cloneDeep = require('lodash.clonedeep');

...

let clonedGlobalState = cloneDeep(globalState);
let foundCompany = clonedGlobalState.companies.list.find(company => company[0].id === id);
foundCompany[1][field].checked = checked;

我建議使用像Lodash 的 cloneDeep這樣的深度克隆 function,因為使用擴展運算符在您的實例中創建副本將在列表數組中創建對象的淺表副本。

克隆 state 后,您可以安全地將其更新為所需的新 state(即無需擔心改變現有的 globalState 對象),然后在調用 setGlobalState 時引用它。

暫無
暫無

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

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