React 기초 [4] : State (2)

yoneeki·2023년 9월 18일

ReactBeginnerMovies

목록 보기
4/14

강의

State Function & Current

<script type="text/babel">
    const root = document.getElementById("root");

    function App() {
      const [counter, setCounter] = React.useState(0);
      const onClick = () => {
        setCounter(counter + 1);
      };
      return (
        <div>
          <h3>Total Clicks : {counter}</h3>
          <button onClick={onClick}>Click Me</button>
        </div>
      );
    }

    ReactDOM.render(<App />, root);
  </script>
  • 지난 코드에서 우리는 counter의 값을 변경하기 위한 방식으로 위와 같은 코드를 작성했다.
  • 하지만 이 코드는 다른 컴포넌트에서 counter가 update될 수 있다는 점에서 그렇게 나이스한 코드가 아니다.
  • 이전 단계의 state를 이용해서 현재 state를 바꾸려고 했을 때, 내 예상과 다른 결과가 나올 수도 있는 것이다.

그러므로 우리는 current 변수를 이용하겠다.

<script type="text/babel">
    const root = document.getElementById("root");

    function App() {
      const [counter, setCounter] = React.useState(0);
      const onClick = () => {
        //setCounter(counter + 1);
        setCounter((current) => current + 1);
      };
      return (
        <div>
          <h3>Total Clicks : {counter}</h3>
          <button onClick={onClick}>Click Me</button>
        </div>
      );
    }

    ReactDOM.render(<App />, root);
  </script>

  • setCounter 함수에서, counter 변수에 바로 접근하지 않고 current에 접근할 것이다.
  • 왜냐하면 counter가 다른 곳에서 업데이트되었을 가능성이 있기 때문이다.
  • 다음 state 값이 현재 값(current)을 바탕으로 나올 수 있게 하는 것이다.
  • 이렇게 작성을 하여야 예상치 못한 업데이트가 어딘가에서 일어났다 하더라도 혼동이 생기는 것을 방지할 수 있다.

그러므로 React.useState(값) 가 우리에게 주는 배열의 인덱스 1의 함수는, current라는 변수를 통해 업데이트가 발생한 인덱스 0의 변수에 접근하는 것이다.

  • 이 배열에서 첫 번째 아이템은 value
  • 이 배열에서 두 번째 아이템은 value를 수정하고 component를 새로고침 할 때 쓰는 함수

Inputs and State

Unit Conversions (단위 변환기)를 만들어 보겠다.

 const MyComponent = () => {
  return (
    <div className="my-container">
      <h1>Hello, React!</h1>
      <p>This is a JSX component.</p>
    </div>
  );
}`
  • 우선 JSX는 HTML과 같은 형식으로 작성한다.

  • 그리고 label은 input 옆에 써주는 글씨다. 이 경우 라벨을 클릭해도 옆에 input이 선택된다.
<script type="text/babel">
    const root = document.getElementById("root");

    function App() {
      return (
        <div>
          <h1>Super Converter</h1>
          <label for="minutes">Minutes</label>
          <input id="minutes" placeholder="Minutes" type="number" />
          <label for="hours">Hours</label>
          <input id="hours" placeholder="Hours" type="number" />
        </div>
      );
    }

    ReactDOM.render(<App />, root);
  </script>
  • 그래서 이렇게 작성하면 될까?
  • React의 세계에서는 위와 같이 코드를 작성하면 안 된다.
  • JSX는 HTML과 "비슷한" 모습을 가졌을 뿐이지 HTML이 아니다.
  • 우리는 지금 리액트를 위해 JSX를 이용하고 있다는 것을 잊으면 안 된다. HTML이 아니라 말이다.

  • 실제로 inspect의 콘솔 창에서 invalid한 Dom property라고 경고한다.

그러므로 우리는 JSX가 HTML과 비슷함에도 불구하고 몇 가지 점에서 크게 다르다는 것을 인지한 후에 코드를 작성해야 한다.

  • class (X) className(O)
  • for (X) htmlFor (O)

한편 React JS에서 input은 uncontrolled라고 알려져 있다.

  • input 내의 value를 우리가 통제할 수 없다는 것이다.
  • 그래서 또한 역시, 우리는 state 기능을 사용해야 할 것이다.


  • 우리는 사용자가 minutes 값을 입력할 때마다 상태를 업데이트하고 싶다.
const [minutes, setMinutes] = React.useState();
  • 이 배열에서 첫 번째 아이템은 value (state로서의 minutes 라는 값)
  • 이 배열에서 두 번째 아이템은 value를 수정하고 component를 새로고침 할 때 쓰는 함수
		<input
            value={minutes}
            id="minutes"
            placeholder="Minutes"
            type="number"
            onChange={onChange}
          />
  • 그리고 minutes라는 state의 값을 input의 value로 넣어주었다.
  • input value = state value
  • 그리고 input에 변화가 생길 때마다(writing things down) 그 변화를 리스닝하고 싶다.
  • input에 대한 변화에 대한 onChange 함수 실행


  • 그래서 우리는 onChange 함수를 수정하여 파라미터에 event를 넣었다.
  • 그랬더니 input value의 변경에 따라 리액트가 무언가 값을 준다.
  • 자세히 보니 Synthetic한 이벤트라고 한다. 리액트가 일종의 가짜 이벤트를 발생시켜 우리에게 정보를 보여주는 것이다.

  • 위 배열 제이슨 값을 자세히 살펴보면 native event라는 실제 이벤트 값에 대한 정보도 있다.
  • 어쨌든 일단은 우리가 간단하게 Event에 접근할 수 있다는 것을 알면 된다.


  • 콘솔창에 찍히는 정보가 너무 많으니 event.target.value라는 값, 즉 내가 입력한 정보만 받아보기로 했다.


  • 우리의 진짜 목적은 input value로서, 그리고 state value로서, minutes 값에 대한 변화에 따라 컴포넌트를 변경시켜, 우리가 의도한 대로 브라우저 화면 출력 값의 변화를 발생시키는 것이다.
  • 그래서 일단 console.log(event.target.value)를 setMinutes(event.target.value)로 변경한다.
  • 잘 되는지 확인하기 위해서 h4 태그 안에 한번 찍어본다.
<script type="text/babel">
    const root = document.getElementById("root");

    function App() {
      const [minutes, setMinutes] = React.useState(0);
      const onChange = (event) => {
        setMinutes(event.target.value);
      };
      const reset = () => setMinutes(0);
      return (
        <div>
          <h1 className="hi">Super Converter</h1>
          <div>
            <label htmlFor="minutes">Minutes</label>
            <input
              value={minutes}
              id="minutes"
              placeholder="Minutes"
              type="number"
              onChange={onChange}
            />
          </div>

          <div>
            <label htmlFor="hours">Hours</label>
            <input
              value={Math.round(minutes / 60)}
              //value={minutes / 60}
              id="hours"
              placeholder="Hours"
              type="number"
              onChange={onChange}
            />
          </div>
          <button onClick={reset}>reset</button>
        </div>
      );
    }

    ReactDOM.render(<App />, root);
  </script>


  • 분에서 시로 바꾸는 기능과 리셋 기능을 추가했다.

Flip Function

그런데 나는 이제 시에서 분으로도 바꾸고 싶다 → Flip Function

<script type="text/babel">
    const root = document.getElementById("root");

    function App() {
      const [minutes, setMinutes] = React.useState(0);
      const [flipped, setFlipped] = React.useState(false);
      const onChange = (event) => {
        setMinutes(event.target.value);
      };
      const reset = () => setMinutes(0);
      const onFlip = () => setFlipped((current) => !current);
      return (
        <div>
          <h1 className="hi">Super Converter</h1>
          <div>
            <label htmlFor="minutes">Minutes</label>
            <input
              value={minutes}
              id="minutes"
              placeholder="Minutes"
              type="number"
              onChange={onChange}
              //disabled={flipped === true} // flipped가 true면 disabled
              disabled={flipped}
            />
          </div>

          <div>
            <label htmlFor="hours">Hours</label>
            <input
              value={Math.round(minutes / 60)}
              //value={minutes / 60}
              id="hours"
              placeholder="Hours"
              type="number"
              onChange={onChange}
              //disabled={flipped === false} // flipped가 false면 disabled
              disabled={!flipped}
            />
          </div>
          <button onClick={reset}>reset</button>
          <button onClick={onFlip}>Flip</button>
        </div>
      );
    }

    ReactDOM.render(<App />, root);
  </script>

  • 우선 시를 클릭하면 분의 클릭이 disabled 되고, 다시 분을 클릭하면 분은 enabled 되면서 시는 disabled 되는 기능을 추가해야 한다.
<script type="text/babel">
    const root = document.getElementById("root");

    function App() {
      const [amount, setAmount] = React.useState(0);
      const [flipped, setFlipped] = React.useState(false);
      const onChange = (event) => {
        setAmount(event.target.value);
      };
      const reset = () => setAmount(0);
      const onFlip = () => setFlipped((current) => !current);

      return (
        <div>
          <h1 className="hi">Super Converter</h1>
          <div>
            <label htmlFor="minutes">Minutes</label>
            <input
              value={flipped ? amount * 60 : amount}
              id="minutes"
              placeholder="Minutes"
              type="number"
              onChange={onChange}
              disabled={flipped}
            />
          </div>

          <div>
            <label htmlFor="hours">Hours</label>
            <input
              // 우리가 지금 flip되어 있다면 그냥 현재 값만 보여줘
              value={flipped ? amount : Math.round(amount / 60)}
              id="hours"
              placeholder="Hours"
              type="number"
              onChange={onChange}
              disabled={!flipped}
            />
          </div>
          <button onClick={reset}>reset</button>
          <button onClick={onFlip}>Flip</button>
        </div>
      );
    }

    ReactDOM.render(<App />, root);
  </script>


  • minutes를 amount로 바꿨다.
  • 그 후에 삼항연산자에 따라 값 변환이 브라우저에 나타나게 했다.
  • minutes는 flipped가 true일 때, hours는 flipped가 false 일 때 값이 나타나면 된다.
profile
Working Abroad ...

0개의 댓글