Introduction to useState

useState의 역사는 recomponent라는 라이브러리부터 시작하였다. 해당 라이브러리는 react팀에 눈에 띄여서 인수되어 함께 react hooks를 개발하게 되었다.

Hooks 개발 이전에는 개발자들은 class로 component를 구현하여 사용해야했다. 하지만 react가 함수 프로그래밍으로 hook을 개발하고부터 코드의 양이 매우 적어지고 훨씬 이해하기 쉬워졌다.

function App() {
  const [item, setItem] = useState(1);
  const incrementItem = () => setItem(item + 1);
  const decrementItem = () => setItem(item - 1);

  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
      <button onClick={incrementItem}>IncrementItem</button>
      <button onClick={decrementItem}>DecrementItem</button>
      <span>{item}</span>
    </div>
  );
}

위는 hook으로 기능을 구현한 함수 프로그래밍이고 아래는 class로 구현한 component이다.

export default class AppUgly extends React.Component {
  state = {
    item: 1
  };
  render() {
    const { item } = this.state;
    return (
      <div className="App">
        <h1>Hello CodeSandbox</h1>
        <h2>Start editing to see some magic happen!</h2>
        <button onClick={this.incrementItem}>IncrementItem</button>
        <button onClick={this.decrementItem}>DecrementItem</button>
        <span>{item}</span>
      </div>
    );
  }
  incrementItem = () =>
    this.setState((state) => {
      return {
        item: state.item + 1
      };
    });
  decrementItem = () =>
    this.setState((state) => {
      return {
        item: state.item - 1
      };
    });
}

둘다 같은 기능을 하지만 calss로 작성한 component와 함수형 hooks으로 작성한 conponent의 이해도와 길이가 눈에띄게 다르다. 이러한 이유로 사람들이 hook을 사용하고 개발하는 이유이다.


useInput

useInput은 기본적으로 input을 업데이트하는 함수이다. 정의한 useInput함수의 반환값은 {value, onChange }인데 이걸 JSX에 pops를 사용하지않고 object destructuring으로 pops정보를 전달할 수 있다. 즉 같은 파일이 아닌 다른 파일에서 작성한 hook을 사용할 수 있다.

const useInput = (initialValue) => {
  const [value, setValue] = useState(initialValue);
  const onChange = (e) => {
    console.log(e.target);
  };
  return { value, onChange };
};

export default function App() {
  const name = useInput("Mr.");
  return (
    <div className="App">
      <h1>Hello</h1>
      <input placeholder="Name" {...name} />
    </div>
  );
}

<aside> 📌 JSX에 object destructuring로 전달하는 값은 JSX pops와 같은 이름으로 값을 전달해야 동작한다.

</aside>

이번에는 useInput에 적합성 평가 기능을 추가해볼 것이다. input에 @이가 들어가면 문자가 써지지 않게 구현할 것이다.

const useInput = (initialValue, validator) => {
  const [value, setValue] = useState(initialValue);
  const onChange = (e) => {
    const {
      target: { value }
    } = e;
    let willUpdate = true;
    if (typeof validator == "function") {
      willUpdate = validator(value);
    }
    if (willUpdate) {
      setValue(value);
    }
  };
  return { value, onChange };
};

export default function App() {
  const maxLen = (value) => !value.includes("@");
  const name = useInput("Mr.", maxLen);
  return (
    <div className="App">
      <h1>Hello</h1>
      <input placeholder="Name" {...name} />
    </div>
  );
}

기존 useInput 파라미터에 validator를 추가하였다. validator는 적합성을 평가하는 함수로 useInput에 전달할때 구현된 함수를 가지고 onChange에서 기능을 하게 된다.

validator에 전달된 함수는 maxLen으로 인수에 @이가 들어가면 false를 반환한다. 그리고 useInput에서 callback으로 사용되는데, callback에 전달된 인수가 input에 수정되는 value인 것이다.

useInput의 onChange는 조건함수가 없으면 모든걸 업데이트하고 있으면 함수 조건에 맞추어 업데이트를 하지 않는다.