왜 즉각 반응하지 않습니까?
29902 단어 reactprogrammingjavascript
그러나 사실은 그렇지 않다.
this.setState
또는 useState
의 상태 업데이트를 사용하면 상태가 즉시 바뀌지 않고 마운트된 상태 전환을 만들 수 있습니다.업데이트 방법을 호출한 후 바로state에 접근하면 이전 값을 되돌릴 수 있습니다.상태 업데이트가 호출되는 동기화 작업을 보장할 수 없습니다. 성능 때문에 여러 상태 업데이트를 일괄 처리할 수 있습니다.
왜 상태 업데이트가 비동기적입니까?
상태 업데이트는 가상 DOM을 변경하고 재구현을 초래하므로 비용이 많이 들 수 있습니다.상태 업데이트 동기화는 대량의 업데이트로 인해 브라우저가 응답하지 않을 수 있습니다.
이러한 문제를 피하기 위해서, 우리는 상태를 다른 단계로 갱신하고, 이러한 업데이트를 일괄 처리하는 것을 신중하게 선택했다.
setState가 완성될 때까지 async await를 사용할 수 있습니까?
setState
가 비동기적이라는 것을 확인했으니 다음에 고려해야 할 문제는 async-await
를 호출한 후 바로 업데이트 상태에 접근하기를 원한다면 setState
와 setState
를 함께 사용하는 것이 유효한가 하는 것이다.결론이 나기 전에 코드 세그먼트에서 다음을 시도해 보겠습니다.
import React, { useState } from "react";
function AppFunctional() {
const [count, setCount] = useState(0);
const handleClick = async () => {
console.log("Functional:Count before update", count);
await setCount(count + 1);
console.log("Functional:Count post update", count);
};
return (
<div className="container">
<h1>Hello Functional Component!</h1>
<p>Press button to see the magic :)</p>
<button onClick={handleClick}>Increment</button>
{!!count && (
<div className="message">You pressed button {count} times</div>
)}
</div>
);
}
class AppClassComp extends React.Component {
state = {
count: 0
};
handleClick = async () => {
const { count } = this.state;
console.log("Class:Count before update", count);
await this.setState({ count: count + 1 });
console.log("Class:Count post update", this.state.count);
};
render() {
const { count } = this.state;
return (
<div className="container">
<h1>Hello Class Component!</h1>
<p>Press button to see the magic :)</p>
<button onClick={this.handleClick}>Increment</button>
{!!count && (
<div className="message">You pressed button {count} times</div>
)}
</div>
);
}
}
export default function App() {
return (
<div className="wrapper">
<AppFunctional />
<AppClassComp />
</div>
);
}
함수와 클래스 구성 요소의 증가 계수가 있을 때의 컨트롤러 출력상기 코드 세그먼트를 실행할 때 컨트롤러에서 보듯이 클래스 구성 요소에서 set State를 호출하면 업데이트 상태에 즉시 접근할 수 있지만, 기능 구성 요소는 async await를 사용한 후에도 이전 상태를 받을 수 있습니다.
그렇다면 왜 상술한 상황에서 우리는 다른 행동을 할 수 있을까?
클래스와 기능 구성 요소에 대한 답이 다르다.우선 클래스 구성 요소의 행동을 알아보자.
setState
의 현재 구현에서 업데이트 프로그램은 await
의 해석을 하기 전에 줄을 서서 이 해석은 기본적으로 반환값을 사용하여 실행한다Promise.resolve
.그래서 setState
약속에 회답하지 않았음에도 불구하고 여전히 유효하다. 이것은 우연한 일치일 뿐이다.그 밖에 그것이 작용하더라도 리액트가 장래에 setState
의 실현을 변경할 때 같은 행위를 보류할 것이라고 보장할 수 없다.async await가 왜 기능 구성 요소와 함께 일을 할 수 없는지 토론하기 전에 다른 해결 방안을 토론합시다.
setTimeout을 가능한 해결 방안으로 간주
우리는 상태 업데이트가 비동기적이라는 것을 알고 있기 때문에, 그것들은 반드시 장래 어느 때에 완성될 것이다.현재, 우리는 충분한 지연 상황에서
setTimeout
를 추가하면 업데이트된 값을 얻을 수 있다고 생각할 수 있습니다.어떤 결론을 내리기 전에 다시 한 번 시도해 봅시다.
import React, { useState } from "react";
function AppFunctional() {
const [count, setCount] = useState(0);
const handleClick = () => {
console.log("Functional:Count before update", count);
setCount(count + 1);
setTimeout(() => {
console.log("Functional:Count post update in setTimeout", count);
}, 1000);
};
console.log("Functional:Count in render", count);
return (
<div className="container">
<h1>Hello Functional Component!</h1>
<p>Press button to see the magic :)</p>
<button onClick={handleClick}>Increment</button>
{!!count && (
<div className="message">You pressed button {count} times</div>
)}
</div>
);
}
class AppClassComp extends React.Component {
state = {
count: 0
};
handleClick = () => {
const { count } = this.state;
console.log("Class:Count before update", count);
this.setState({ count: count + 1 });
setTimeout(() => {
console.log("Class:Count post update in setTimeout", this.state.count);
}, 1000);
};
render() {
const { count } = this.state;
return (
<div className="container">
<h1>Hello Class Component!</h1>
<p>Press button to see the magic :)</p>
<button onClick={this.handleClick}>Increment</button>
{!!count && (
<div className="message">You pressed button {count} times</div>
)}
</div>
);
}
}
export default function App() {
return (
<div className="wrapper">
<AppFunctional />
<AppClassComp />
</div>
);
}
setTimeout을 사용하여 함수와 클래스 구성 요소의 계수를 증가시킬 때 컨트롤러 출력클래스 구성 요소
setTimeout
리셋의 상태에 대해 업데이트된 값이 있지만, 함수 구성 요소는 업데이트된 값을 반영하지 않습니다.그러나 기능 구성 요소에서 재미있는 일이 일어났다.구성 요소 내부에 있는
console.log(count)
에서 업데이트된 값을 표시합니다. setTimeout
in render console.log()
에서 리셋된 후에도 이전 값을 표시합니다.이것은 우리로 하여금 다음과 같은 결론을 얻게 한다.
비록 우리는 상태 갱신이 비동기적이라고 생각하지만, 우리는 단지 부분적으로 정확할 뿐이다.
이 문제를 이해하다
이것은 모두 폐쇄에 관한 것이다.
기능 구성 요소에 대해 상태 값은 현재 클립된 함수에서 사용됩니다. 상태가 백엔드에서 업데이트되었을 수도 있지만, 현재 클립된 값은 업데이트된 값을 인용할 수 없습니다.업데이트된 값은 다음 렌더링 주기에 반영되며, 이 값에 대한 새로운 클립을 생성합니다. 현재 클립은 변하지 않습니다.
따라서
setTimeout
에서 오래 기다려도 업데이트된 값은 리셋에서 사용할 수 없고 같은 이유async-await
도 기능 구성 요소의 상태 업데이트 프로그램에 적용되지 않는다.Setstate를 호출한 후에 업데이트된 값에 접근하려면 어떻게 해야 합니까?
Class
및 Functional
구성 요소의 솔루션이 다릅니다.클래스 어셈블리의 경우
async-await
와setTimeout
모두 작업을 할 수 있지만 setState
호출 후 업데이트 상태에 접근하는 정확한 방법은 다음과 같은 방법 중 하나이다.setState
리셋`설정상태 takes a callback as the second argument which is invoked when the state update has completed. Use this to either log or call a function with the updated state.
설정상태(()=>{}, 리셋)`componentDidUpdate
.현재와 이전의 상태를 비교한 후에도 componentDidUpdate
에서 부작용(조작)을 수행할 수 있다.기능 구성 요소
기능 구성 요소는 클립에 심각하게 의존합니다. 업데이트된 값에 접근하기 위해서 클립을 돌파해야 합니다.업데이트 상태에 액세스하기 위한 몇 가지 권장 방법은 다음과 같습니다.
useEffect
연결.상태를 의존항으로 추가하고 업데이트된 상태를 방문하여 업데이트된 상태 값을 기록하거나 업데이트된 상태 값을 사용하여 부작용을 수행할 수 있습니다.제공된 솔루션에 대한 자세한 내용은 코드 세그먼트를 참조하십시오.
import React, { useState } from "react";
import "./style.scss";
export default class App extends React.Component {
state = {
count: 0
};
handleClick = () => {
const { count } = this.state;
console.log("Count before update", count);
this.setState({ count: count + 1 }, () => {
console.log("Count state in setState callback", this.state.count);
// call an action with updated state here
});
};
componentDidUpdate(_, prevState) {
if (prevState.count !== this.state.count) {
console.log("Count state in componentDidUpdate", this.state.count);
// call any side-effect here
}
}
render() {
const { count } = this.state;
console.log("Count state in render", count);
return (
<div className="container">
<h1>Hello Class Component!</h1>
<p>Press button to see the magic :)</p>
<button onClick={this.handleClick}>Increment</button>
{!!count && (
<div className="message">You pressed button {count} times</div>
)}
</div>
);
}
}
우리가 업데이트된 상태를 즉시 사용할 수 없을 때, 이것이 바로 우리가 알아야 할 전부이다.핵심 배달
useEffect
는 상태가 업데이트되었을 때 이 함수를 호출하여 업데이트된 상태 값에 접근할 수 있는 리셋 함수를 제공합니다.this.setState
또는 useEffect
로 업데이트된 값에 접근할 수 있습니다.읽어주셔서 감사합니다.
만약 본문에 대해 어떤 의문이나 건의가 있으면 언제든지 평론을 발표하거나 평론을 발표하십시오
Reference
이 문제에 관하여(왜 즉각 반응하지 않습니까?), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/shubhamreacts/why-don-t-react-state-updates-reflect-immediately-2o27텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)