[英]How does calling "setState" as a callback in a function, without any new state value, successfully update the state?
[英]Why does calling one `setState` function update an entirely separate state value?
我遇到一個問題,其中一個setState
function 正在更新兩個單獨的 state 值。
我正在嘗試制作一個小型 React 可排序數組。 該程序的行為應如下所示:
unsortedData
和displayedData
state 鈎子中displayedData
中的數組被排序(使用.sort()
)displayedData
設置為與unsortedData
相同的值 - 恢復原始順序但是,在第一次單擊切換排序時,它會同時對unsortedData
和displayedData
進行排序,這意味着我丟失了原始數據順序。 我知道我可以存儲他們的訂單,但我想知道為什么這些 state 值看起來是耦合的。
Stackblitz 工作代碼在這里。
GIF 在這里顯示問題
我找不到發生這種情況的地方。 我看不到任何對象/數組引用正在進行(我正在傳播新對象/數組)。
代碼在這里:
const Test = () => {
const [unsortedData, setUnsortedData] = useState([])
const [displayedData, setDisplayedData] = useState([])
const [isSorted, setisSorted] = useState(false)
const handleSorting = () => setisSorted(!isSorted)
useEffect(() => {
if (isSorted === true) setDisplayedData([...unsortedData.sort()]) // sort data
if (isSorted === false) setDisplayedData([...unsortedData]) // restore original data order
}, [isSorted, unsortedData])
useEffect(() => {
const mockData = [3, 9, 6]
setUnsortedData([...mockData]) // store original data order in "unsortedData"
setDisplayedData([...mockData])
}, [])
return (
<div>
{displayedData.map(item => item)}
<br />
<button onClick={() => handleSorting()}>Toggle sorting</button>
</div>
)
}
.sort
function 改變數組,所以當你這樣做時:
setDisplayedData([...unsortedData.sort()])
你正在改變 unsortedData,然后復制它。 由於您改變了原始數組,因此該更改可以在組件重新呈現時顯示在屏幕上。
因此,最低限度的解決方法是先復制,然后再排序:
setDisplayedData([...unsortedData].sort())
另外,為什么我需要 useEffect? 為什么我不能將 useEffect 的內容(其中包含 if 語句)移動到 handleSorting function 中?
將它移動到 handleSorting 應該是可能的,但實際上我想提出另一種選擇:只有兩種狀態,未排序的數據和是否排序的 boolean。 然后顯示的數據是基於這兩者的計算值。
const [unsortedData, setUnsortedData] = useState([3, 9, 6]) // initialize with mock data
const [isSorted, setisSorted] = useState(false)
const displayedData = useMemo(() => {
if (isSorted) {
return [...unsortedData].sort();
} else {
return unsortedData
}
}, [unsortedData, isSorted]);
const handleSorting = () => setisSorted(!isSorted)
// No use useEffect to sort the data
// Also no useEffect for the mock data, since i did that when initializing the state
這種方法的好處是
如果您只想在用戶按下按鈕時向用戶顯示已排序的數組,您可以使用此代碼語句(最初是從vue3 todo list 復制的)
const filters = {
none: (data) => [...data],
sorted: (data) => [...data].sort((a, b) => a - b),
}
const Test = () => {
const [unsortedData, setUnsortedData] = useState([])
const [currentFilter, setCurrentFilter] = useState('none')
useEffect(() => {
const mockData = [3, 9, 6]
setUnsortedData([...mockData])
}, [])
return (
<div>
<ul>
{/* All magic is going here! */}
{filters[currentFilter](unsortedData).map(item => <li key={item}>{item}</li>)}
</ul>
<br />
<button
onClick={() =>
setCurrentFilter(currentFilter === 'none' ? 'sorted' : 'none')}>
Toggle sorting
</button>
</div>
)
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.