[英]setState doesn't update the state immediately
我想問一下為什么當我執行onClick
事件時我的狀態沒有改變。 我前段時間搜索過,我需要在構造函數中綁定onClick
函數,但狀態仍未更新。
這是我的代碼:
import React from 'react';
import Grid from 'react-bootstrap/lib/Grid';
import Row from 'react-bootstrap/lib/Row';
import Col from 'react-bootstrap/lib/Col';
import BoardAddModal from 'components/board/BoardAddModal.jsx';
import style from 'styles/boarditem.css';
class BoardAdd extends React.Component {
constructor(props) {
super(props);
this.state = {
boardAddModalShow: false
};
this.openAddBoardModal = this.openAddBoardModal.bind(this);
}
openAddBoardModal() {
this.setState({ boardAddModalShow: true }); // set boardAddModalShow to true
/* After setting a new state it still returns a false value */
console.log(this.state.boardAddModalShow);
}
render() {
return (
<Col lg={3}>
<a href="javascript:;"
className={style.boardItemAdd}
onClick={this.openAddBoardModal}>
<div className={[style.boardItemContainer,
style.boardItemGray].join(' ')}>
Create New Board
</div>
</a>
</Col>
);
}
}
export default BoardAdd
您的狀態需要一些時間來改變,並且由於console.log(this.state.boardAddModalShow)
在狀態改變之前執行,您將獲得先前的值作為輸出。 所以需要在setState
函數的回調中寫console
openAddBoardModal() {
this.setState({ boardAddModalShow: true }, function () {
console.log(this.state.boardAddModalShow);
});
}
setState
是異步的。 這意味着您不能在一行調用它並假設狀態在下一行發生了變化。
根據React 文檔
setState()
不會立即改變this.state
而是創建一個掛起的狀態轉換。 調用此方法后訪問this.state
可能會返回現有值。 無法保證對 setState 調用的同步操作,並且可能會批量調用以提高性能。
setState
異步這是因為
setState
會改變狀態並導致重新渲染。 這可能是一項昂貴的操作,並且使其同步可能會使瀏覽器無響應。因此
setState
調用是異步的,並且是批處理的,以獲得更好的 UI 體驗和性能。
幸運的是setState()
需要一個回調。 這就是我們獲得更新狀態的地方。
考慮這個例子。
this.setState({ name: "myname" }, () => {
//callback
console.log(this.state.name) // myname
});
所以當回調觸發時, this.state 是更新的狀態。
您可以在回調中獲取mutated/updated
數據。
由於 setSatate 是一個異步函數,因此您需要像這樣將狀態作為回調進行控制台。
openAddBoardModal(){
this.setState({ boardAddModalShow: true }, () => {
console.log(this.state.boardAddModalShow)
});
}
setState()
並不總是立即更新組件。 它可能會批量更新或推遲更新。 這使得在調用setState()
之后立即讀取 this.state 成為一個潛在的陷阱。 相反,使用componentDidUpdate
或setState
回調( setState(updater, callback)
),這兩者都保證在應用更新后觸發。 如果您需要根據之前的狀態設置狀態,請閱讀下面的更新程序參數。
setState()
將始終導致重新渲染,除非shouldComponentUpdate()
返回 false。 如果正在使用可變對象並且在shouldComponentUpdate()
無法實現條件渲染邏輯,則僅在新狀態與先前狀態不同時調用setState()
將避免不必要的重新渲染。
第一個參數是帶有簽名的更新程序函數:
(state, props) => stateChange
state
是對應用更改時組件狀態的引用。 它不應該被直接變異。 相反,應該通過基於 state 和 props 的輸入構建一個新對象來表示更改。 例如,假設我們想通過 props.step 增加 state 中的一個值:
this.setState((state, props) => {
return {counter: state.counter + props.step};
});
對於嘗試使用鈎子執行此操作的任何人,您都需要useEffect
。
function App() {
const [x, setX] = useState(5)
const [y, setY] = useState(15)
console.log("Element is rendered:", x, y)
// setting y does not trigger the effect
// the second argument is an array of dependencies
useEffect(() => console.log("re-render because x changed:", x), [x])
function handleXClick() {
console.log("x before setting:", x)
setX(10)
console.log("x in *line* after setting:", x)
}
return <>
<div> x is {x}. </div>
<button onClick={handleXClick}> set x to 10</button>
<div> y is {y}. </div>
<button onClick={() => setY(20)}> set y to 20</button>
</>
}
輸出:
Element is rendered: 5 15
re-render because x changed: 5
(press x button)
x before setting: 5
x in *line* after setting: 5
Element is rendered: 10 15
re-render because x changed: 10
(press y button)
Element is rendered: 10 20
這個回調真的很亂。 只需使用 async await 代替:
async openAddBoardModal(){
await this.setState({ boardAddModalShow: true });
console.log(this.state.boardAddModalShow);
}
如果您想跟蹤狀態是否正在更新,那么另一種做同樣事情的方法是
_stateUpdated(){
console.log(this.state. boardAddModalShow);
}
openAddBoardModal(){
this.setState(
{boardAddModalShow: true},
this._stateUpdated.bind(this)
);
}
通過這種方式,您可以在每次嘗試更新狀態以進行調試時調用方法“_stateUpdated”。
將
setState()
視為更新組件的請求而不是立即命令。 為了獲得更好的感知性能,React 可能會延遲它,然后一次更新多個組件。 React 不保證狀態更改會立即應用。
檢查這個以獲取更多信息。
在您的情況下,您已發送更新狀態的請求。 React 需要時間來響應。 如果您嘗試立即console.log
狀態,您將獲得舊值。
setState()
是異步的。 驗證狀態是否正在更新的最佳方法是在componentDidUpdate()
而不是在this.setState({ boardAddModalShow: true })
之后放置console.log(this.state.boardAddModalShow)
this.setState({ boardAddModalShow: true })
。
將 setState() 視為更新組件的請求而不是立即命令。 為了獲得更好的感知性能,React 可能會延遲它,然后一次更新多個組件。 React 不保證立即應用狀態更改
根據React 文檔
React 不保證狀態更改會立即應用。 這使得在調用 setState() 后立即讀取 this.state 成為一個潛在的
pitfall
並且由於async
性質可能返回existing
值。 相反,使用componentDidUpdate
或在 setState 操作成功后立即執行的setState
回調。通常我們建議使用componentDidUpdate()
代替此類邏輯。
import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";
class App extends React.Component {
constructor() {
super();
this.state = {
counter: 1
};
}
componentDidUpdate() {
console.log("componentDidUpdate fired");
console.log("STATE", this.state);
}
updateState = () => {
this.setState(
(state, props) => {
return { counter: state.counter + 1 };
});
};
render() {
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<button onClick={this.updateState}>Update State</button>
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
setState是一個異步函數,因此您可能需要將其用作,
this.setState({key:value},()=>{ callYourFunction(this.state.key) });
openAddBoardModal=async()=>{
await this.setState({ boardAddModalShow: true });
console.log(this.state.boardAddModalShow);
}
盡管有很多很好的答案,但如果有人在此頁面上搜索useState
替代方法來實現 UI 組件,例如應根據用戶輸入打開或關閉的導航抽屜,則此答案會有所幫助。
雖然useState
看起來很方便,但狀態不是立即設置的,因此,您的網站或應用程序看起來很慢……如果您的頁面足夠大,react 將需要很長時間來計算狀態更改時應更新的所有內容。 ..
我的建議是當您希望 UI 響應用戶操作而立即更改時,使用 refs 並直接操作 DOM。
在反應的情況下,為此目的使用狀態確實是一個壞主意。
上述解決方案不適用於 useState 鈎子。 可以使用下面的代碼
setState((prevState) => {
console.log(boardAddModalShow)
// call functions
// fetch state using prevState and update
return { ...prevState, boardAddModalShow: true }
});
當我運行代碼並在控制台檢查我的輸出時,它顯示它是未定義的。 在我四處搜索並找到對我有用的東西之后。
componentDidUpdate(){}
我在constructor()之后的代碼中添加了這個方法。 查看 React Native 工作流的生命周期。
this.setState({
isMonthFee: !this.state.isMonthFee,
}, () => {
console.log(this.state.isMonthFee);
})
是的,因為 setState 是一個異步函數。 在您編寫 set state 后立即設置 state 的最佳方法是使用 Object.assign 像這樣:例如,您想將一個屬性 isValid 設置為 true,請這樣做
Object.assign(this.state, { isValid: true })
您可以在編寫此行后立即訪問更新狀態。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.