[英]How to pass react props/state of parent by reference, not value?
我正在使用反應鈎子並嘗試將父級的 state 傳遞給多個組件。 問題是當我想通過 state 的組件本身是 state 的一部分時。 我創建了一個示例來說明我的問題,我有一個按鈕可以增加計數器並將另一個按鈕附加到列表中。 我想查看顯示的按鈕列表,並且都從 state 讀取相同的計數器值,但是當我 append 一個新按鈕時,計數器的值總是在創建按鈕時按值傳遞,它不更新。 在我的項目中(此處未顯示),我通過將函數傳遞給組件以檢索父 state 並手動更新所有組件來規避此問題,但是這樣做我覺得我真的違反了不必要的反應的設計原則復雜的代碼會導致更多的問題。
我的按鈕示例:
import React from 'react'
function Button(props){
return <button onClick={()=>{
// increment the counter
props.setcounter(cur=>cur+1);
// add another button
// these props are not passed by reference: how do I pass these by reference?
props.setitems(items=>items.concat(<tr><td><Button {...props}/></td></tr>))
}}>
{props.counter}
</button>
}
function App() {
const [items,setitems]=React.useState([]);
const [counter,setcounter]=React.useState(0);
return (
<div className="App">
<table>
<th><td>Button with props passed by reference:</td></th>
<tr><td><Button counter={counter} setcounter={setcounter} setitems={setitems} /></td></tr>
</table>
<table>
<th><td>Button with props passed by value:</td></th>
{items}
</table>
</div>
);
}
export default App;
function Button(props){ return <button onClick={()=>{ // increment the counter props.setcounter(cur=>cur+1); // add another button // these props are not passed by reference: how do I pass these by reference? props.setitems(items=>items.concat(<tr><td><Button {...props}/></td></tr>)) }}> {props.counter} </button> } function App() { const [items,setitems]=React.useState([]); const [counter,setcounter]=React.useState(0); return ( <div className="App"> <table> <th><td>Button with props passed by reference:</td></th> <tr><td><Button counter={counter} setcounter={setcounter} setitems={setitems} /></td></tr> </table> <table> <th><td>Button with props passed by value:</td></th> {items} </table> </div> ); } ReactDOM.render( <App />, document.getElementById("root") );
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script> <div id="root"></div>
它能做什么:
當我多次單擊頂部按鈕時,它每次都會使用計數器的當前值創建一個新按鈕,但它不會通過引用傳遞,因此不會在計數器值更新時更新。
我想要它做什么:
所有新創建的按鈕都應該具有相同的計數器值,因為我希望它通過引用傳遞,而不是單擊按鈕時的值。 當我單擊任何按鈕時,應該創建一個新按鈕,並且每個按鈕上的值都應該更新以匹配新的計數器值。
問題是當我想通過 state 的組件本身是 state 的一部分時。
這確實是問題所在,並且正如您所發現的那樣,React 中的反模式會產生陳舊的值。 理想情況下,您不應該在 state 中保留任何組件,如果您這樣做,它們必須是完全純凈的(即在其生命周期內不會收到新的道具)。
當您調用此 state 設置器時實際發生了什么:
props.setitems(items=>items.concat(<tr><td><Button {...props}/></td></tr>))
這是嗎,假設它是第一次被調用:
<Button counter={0} ... />
不僅該按鈕的計數器只有值0
,而且它創建的任何按鈕都將具有相同的值。 你所說的在 React 上下文中實際上沒有意義,因為整個要點是打破引用(以及更普遍的嚴格相等)以觸發重新渲染和效果。
我們希望保持我們的 state 不可變,這意味着重新創建它的任何部分,這些部分在每次渲染時都會發生變化。 對於您正在做的工作,您必須通過在創建新按鈕時循環與items
長度一樣多的次數來重新創建整個按鈕存儲。
您應該考慮的方式是如何從數據中派生 UI,而不是將其存儲為數據:
function Button(props){ return <button onClick={()=>{ props.setcounter(cur=>cur+1); props.setitems(items=> [...items, 1]) }}> {props.counter} </button> } function App() { const [items,setitems]=React.useState([1]); const [counter,setcounter]=React.useState(0); return ( <div className="App"> {items.map(() => <Button counter={counter} setcounter={setcounter} setitems={setitems}/>)} </div> ); } ReactDOM.render( <App />, document.getElementById("root") );
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script> <div id="root"></div>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.