React中使用useState()導致的問題記錄


https://www.jianshu.com/p/d9158074176b

場景一: 更新 state 的一個對象(或數組)屬性的某個子屬性或值。

使用 Hook Function Component

function App() { const [arr, updateArr] = useState([]); const addList = () => { arr.push('Hello React'); updateArr(arr); }; return ( <div> { arr.map((item, index) => ( <p key={index}>{index} {item}</p> )) } <button onClick={addList}>添加List</button> </div> ); } 

使用 Class Component

class App extends Component { constructor(props) { super(props); this.state = { arr: [] } } addList = () => { let arr = this.state.arr; arr.push('Hello React'); this.setState({ arr: arr }, () => { console.log(this.state.arr); }); }; deleteList = () => { const { arr } = this.state; arr.splice(0, 1); this.setState({ arr: arr }, () => { console.log(this.state.arr); }); }; render() { const { arr } = this.state; return ( <div> { arr.map((item, index) => ( <p key={index}>{index} {item}</p> )) } <button onClick={this.addList}>添加List</button> <button onClick={this.deleteList}>刪除List</button> </div> ); } } 

結果:使用 Hook Function Component push 數組后數組長度並沒有改變,使用Class Component正常。
原因:在 Hook 中直接修改 state 的一個對象(或數組)屬性的某個子屬性或值,然后直接進行 set,不會觸發重新渲染。

  • 對 Class Component來說,state 是 Immutable 的,setState 后一定會生成一個全新的 state 引用。它是通過 this.state 方式讀取 state,所以每次代碼執行都會拿到最新的 state 引用。
  • 對 Hook Function Component 而言,useState 產生的數據也是 Immutable 的,通過數組第二個參數 Set 一個新值后,原來的值會形成一個新的引用在下次渲染時。

解決方案

改變引用地址

function App() { const [arr, updateArr] = useState([]); const addList = () => { arr.push('Hello React'); // 通過擴展運算符實現深拷貝 updateArr([...arr]); }; return ( <div> { arr.map((item, index) => ( <p key={index}>{index} {item}</p> )) } <button onClick={addList}>添加List</button> </div> ); } 

場景二: 在setTimeout中更改state。

使用 Hook Function Component

function App() { const [count, updateCount] = useState(0); useEffect(() => { let timer = setTimeout(() => { updateCount(1); getCount(); }, 1000); return () => { clearTimeout(timer); } }, []); const getCount = () => { console.log(count); // result: 0 }; return ( <div>{count}</div> ); } 

使用 Class Component

let timer = null; export default class App extends Component { constructor(props) { super(props); this.state = { count: 0 } } componentDidMount() { timer = setTimeout(() => { this.setState({ count: 1 }) this.getCount(); }, 1000); } getCount = () => { console.log(this.state.count); // result: 1 } componentWillUnmount() { clearTimeout(timer); } render() { const { count } = this.state; console.log(count); // result: 1 return ( <div>{count}</div> ); } } 

結果:使用 Hook Function Component 更改count后,頁面顯示1,getCount方法中打印的count為0,使用Class Component更改count后頁面顯示1,getCount方法中打印的count為1。
原因:Hook Function Comoponent中由於對 state 的讀取沒有通過 this. 的方式,使得每次 setTimeout 都讀取了當時渲染閉包環境的數據,雖然最新的值跟着最新的渲染變了,但舊的渲染里,狀態依然是舊值。

解決方案

使用ref

function App() { const [count, updateCount] = useState(0); useEffect(() => { let timer = setTimeout(() => { updateCount(1); getCount(); }, 1000); return () => { clearTimeout(timer); } }, []); let ref = useRef(); ref.current = count; const getCount = () => { console.log(ref.current); // result: 1 }; return ( <div>{count}</div> ); } 

The End~

附上我認為比較值得研讀的相關文章:

1.react-hook-usestate-setState
2.精讀《Function Component 入門》


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM