반응 후크: useState

19304 단어
React 후크를 사용하면 클래스 구성 요소를 사용하는 것보다 훨씬 깔끔한 코드를 만들 수 있습니다(최대 90% cleaner ).

오늘은 동일한 카운터 구성 요소의 두 버전을 비교하여 useState 후크를 살펴보겠습니다. 그 중 하나는 클래스 구문을 사용하여 작성되고 다른 하나는 후크를 사용하여 작성됩니다.

카운터(클래스): https://codepen.io/alveem/pen/VwayxYx

카운터(후크): https://codepen.io/alveem/pen/OJNzvqa



소개



클래스 기반 카운터의 코드는 다음과 같습니다.

class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    }
  }

  increase = () => {
    this.setState({ count: this.state.count + 1 })
  }

  decrease = () => {
    this.setState({ count: this.state.count - 1 })
  }  

  reset = () => this.setState({ count: 0 })

  render() {
    return (
      <div className="counter">
        <p className="count">{this.state.count}</p>
        <div className="controls">
          <button onClick={this.increase}>Increase</button>
          <button onClick={this.decrease}>Decrease</button>
          <button onClick={this.reset}>Reset</button>
        </div>
      </div>
    );
  }
}
useState 버전은 다음과 같습니다.

const Counter = () => {
  const [count, setCount] = React.useState(0);

  const increase = () => setCount(count + 1);
  const decrease = () => setCount(count - 1);
  const reset = () => setCount(0);

  return (
    <div className="counter">
      <p className="count">{count}</p>
      <div className="controls">
        <button onClick={increase}>Increase</button>
        <button onClick={decrease}>Decrease</button>
        <button onClick={reset}>Reset</button>
      </div>
    </div>
  )
}
useState 메서드는 초기 상태 값을 받아 첫 번째 요소가 상태에 대한 참조이고 두 번째 요소가 상태를 변경하는 함수인 배열을 반환합니다.

코드를 더 깔끔하게 만들기 위해 배열을 분해하고 있습니다. 다음과 동일합니다.

const countStateArray = React.useState(0);
const count = countStateArray[0];
const setCount = countStateArray[1];

비동기성



상태 변경의 비동기 동작이 후크의 영향을 받는지 살펴보겠습니다.

클래스 컴포넌트



지금 2 대신 1만큼 카운터를 늘리고 싶습니다. this.setState 메서드에 다른 increase 문을 추가해 보겠습니다.

increase = () => {
  this.setState({ count: this.state.count + 1 })
  this.setState({ count: this.state.count + 1 })
}

그러나 카운터는 1가 비동기이기 때문에 여전히 setState만큼만 증가합니다. setStateObject.assign를 사용하여 상태 업데이트를 할당하므로 다음과 같이 끝납니다.

Object.assign(
  this.state,   // current state { count: 0 }
  { count: 1 }, // first state update
  { count: 1 }, // second state update
)

일치하는 키가 전달된 마지막 개체Object.assign는 원래 개체의 값을 업데이트하는 데 사용됩니다.

대신 setState에 함수를 전달해 보겠습니다.

increase = () => {
  this.setState(state => ({ count: state.count + 1 }))
  this.setState(state => ({ count: state.count + 1 }))
}

이제 카운터가 2만큼 증가합니다.

기능성 성분



이제 useState 를 사용하여 동일한 작업을 수행하려고 합니다. setCount 메서드 내에서 두 번째로 increase를 호출합니다.

const increase = () => {
  setCount(count + 1)
  setCount(count + 1)
}

그리고 카운터는 1 만큼만 증가합니다. 따라서 이것은 클래스 구성 요소에서 객체를 setState에 전달했을 때와 동일한 방식으로 작동합니다.

다행히도 setCount 함수는 다른 형식을 가질 수도 있습니다.

const increase = () => {
  setCount(prevCount => prevCount + 1)
  setCount(prevCount => prevCount + 1)
}

이제 작동하며 카운터가 2만큼 증가합니다.

차이점


setState의 동작과 useState에 의해 반환된 setter 함수(이 예제에서는 setCount 함수)에 몇 가지 차이점이 있습니다.

소품 받기


setState 메서드는 전달된 콜백 함수의 두 번째 인수로 props를 전달합니다.
this.setState((state, props) => console.log(props))

상태 업데이트 동작



위에서 언급한 대로 setState는 객체를 병합하여 상태를 업데이트합니다. 후크는 전체 상태를 대체합니다.

카운터의 decrease 메서드를 제한하여 0 아래로 내려가지 않도록 합시다.


클래스 구성 요소(setState)

다음은 메서드가 클래스 구성 요소에서 보이는 것입니다.

decrease = () => {
    this.setState(prevState => {
      if (prevState.count <= 0) return;
      this.setState({ count: prevState.count - 1})
    })
  }

3행에서는 아무 것도 반환하지 않습니다. React가 이전 상태를 반환된 것과 병합하기 때문에 상태는 여전히 업데이트됩니다.


기능 구성 요소(useState)

기능적 구성 요소에서 유사한 작업을 수행하면 어떻게 됩니까?

const decrease = () => setCount(prevCount => {
    if (prevCount <= 0) return;
    return prevCount - 1;
  })

카운터가 0에 있을 때 이를 줄이려고 하면 숫자가 사라집니다.
undefined에 전달된 콜백 함수에서 반환하는 모든 것이 새 상태로 설정되기 때문에 새 상태는 setCount로 설정됩니다. 그리고 카운터를 높이려고 하면 NaN 가 됩니다.

대신 새 값이 setState 에서처럼 자동으로 병합되지 않기 때문에 전체 새 상태를 반환해야 합니다.

const decrease = () => setCount(prevCount => {
    if (prevCount <= 0) return 0;
    return prevCount - 1;
  })

이제 예상대로 작동합니다.
useState에서 여러 값이 있는 개체를 사용하는 경우 새 키-값 쌍과 함께 이전 키-값 쌍을 포함하는 새 개체를 전달해야 합니다.

복잡한 상태를 관리하려면 Hooks docs에서 useReducer를 사용하는 것이 좋습니다.

추가 자료


  • React Hooks Docs
  • Should I Use Multiple State Variables in useState ?

  • Rules of Hooks (문서에서)
  • 루프, 조건 또는 중첩 함수 내에서 Hooks를 호출하지 마십시오.
  • 일반 JavaScript 함수에서 후크를 호출하지 마십시오.

  • 좋은 웹페이지 즐겨찾기