왜 즉각 반응하지 않습니까?

React를 사용할 때, 많은 사람들이 상태 변경이 클래스와 React 갈고리가 있는 기능 구성 요소에 즉각 반영되기를 희망한다.
그러나 사실은 그렇지 않다.this.setState 또는 useState의 상태 업데이트를 사용하면 상태가 즉시 바뀌지 않고 마운트된 상태 전환을 만들 수 있습니다.업데이트 방법을 호출한 후 바로state에 접근하면 이전 값을 되돌릴 수 있습니다.
상태 업데이트가 호출되는 동기화 작업을 보장할 수 없습니다. 성능 때문에 여러 상태 업데이트를 일괄 처리할 수 있습니다.

왜 상태 업데이트가 비동기적입니까?


상태 업데이트는 가상 DOM을 변경하고 재구현을 초래하므로 비용이 많이 들 수 있습니다.상태 업데이트 동기화는 대량의 업데이트로 인해 브라우저가 응답하지 않을 수 있습니다.
이러한 문제를 피하기 위해서, 우리는 상태를 다른 단계로 갱신하고, 이러한 업데이트를 일괄 처리하는 것을 신중하게 선택했다.

setState가 완성될 때까지 async await를 사용할 수 있습니까?

setState가 비동기적이라는 것을 확인했으니 다음에 고려해야 할 문제는 async-await를 호출한 후 바로 업데이트 상태에 접근하기를 원한다면 setStatesetState를 함께 사용하는 것이 유효한가 하는 것이다.
결론이 나기 전에 코드 세그먼트에서 다음을 시도해 보겠습니다.
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를 호출한 후에 업데이트된 값에 접근하려면 어떻게 해야 합니까?

ClassFunctional 구성 요소의 솔루션이 다릅니다.

클래스 어셈블리의 경우

async-awaitsetTimeout 모두 작업을 할 수 있지만 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 연결.상태를 의존항으로 추가하고 업데이트된 상태를 방문하여 업데이트된 상태 값을 기록하거나 업데이트된 상태 값을 사용하여 부작용을 수행할 수 있습니다.
  • 돌연변이 참고를 사용합니다.이 해결 방안은ref에서 상태 값을 보존하는 복제를 포함하고 정기적으로 업데이트합니다.ref는 변이이기 때문에 클립의 영향을 받지 않고 업데이트된 값을 저장할 수 있습니다.업데이트 상태 후 액세스 상태와는 직접적인 관계가 없지만, 초기 렌더링
  • 에만 생성된 이벤트 탐지기나 구독 리셋에서 업데이트 상태에 접근하기를 원할 때 유용합니다.
    제공된 솔루션에 대한 자세한 내용은 코드 세그먼트를 참조하십시오.
    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>
        );
      }
    }
    
    
    우리가 업데이트된 상태를 즉시 사용할 수 없을 때, 이것이 바로 우리가 알아야 할 전부이다.

    핵심 배달

  • React의 상태 업데이트는 비동기적입니다. 렌더링은 비싼 작업이기 때문에 상태 업데이트를 동기화하면 브라우저가 응답하지 않을 수 있습니다.
  • useEffect는 상태가 업데이트되었을 때 이 함수를 호출하여 업데이트된 상태 값에 접근할 수 있는 리셋 함수를 제공합니다.
  • 기능 구성 요소의 상태 업데이트는 클립의 영향을 받아 다음 렌더링 주기에 업데이트된 값만 받을 수 있습니다.
  • react 갈고리가 있는 기능 구성 요소에 대해서는 this.setState 또는 useEffect로 업데이트된 값에 접근할 수 있습니다.
  • 가능하면 업데이트 상태에 사용할 값을 매개 변수로 업데이트 상태 후 바로 호출하는 함수로 직접 전달하려고 시도합니다.
  • 읽어주셔서 감사합니다.


    만약 본문에 대해 어떤 의문이나 건의가 있으면 언제든지 평론을 발표하거나 평론을 발표하십시오

    좋은 웹페이지 즐겨찾기