[React] Movie-app Notes - State Practice

31772 단어 Reactnomad coderReact

📒 Nomad Coder ReactJS로 영화 웹 서비스 만들기
강의노트 (2021 Updated ver.)


# 4. State Practice

Converter 만들기

분 -> 시간, 시간 -> 분으로 환산하는 변환기를 만들어보자.

1. State 생성

const [minutes, setMinutes] = React.useState();
const onChange = (e) => {
      setMinutes(e.target.value);
    }

minutes에는 아무 값도 선언하지 않았고, onChange함수를 선언해 이벤트 발생 시 target(=input)의 값을 state의 값으로 set하도록 설정했다.

2. return (UI)

<div>
  <h1 className="title">Converter</h1>
  <label htmlFor="min">Minutes </label>
  <input
        id="min"
	placeholder="Minutes"
	type="number"
	value={minutes} // state val === input val
	onChange={onChange} // onChange: 변화가 있을 때마다 감지하는 func 
  />
  <h4>You are going to convert {minutes} to</h4>
  <label htmlFor="hrs">Hours </label>
  <input id="hrs" placeholder="Hours" type="number" />
</div>

📌 Check Point

JavaScipt가 선점한 단어를 JSX에서 쓰면 오류가 발생한다. 둘은 엄연히 다른 언어이다.
JSX에서 label의 속성으로 for을 쓰면 오류가 발생한다. 이는 JS 언어이기 때문이다. 마찬가지로 class를 쓰면 오류가 발생한다.
JSX에서 해당 속성을 부여하기 위해서는 아래와 같이 적용해야 한다.

    <JS>       <JSX>  
    for   === HtmlFor
    class === ClassName

가장 처음 선언한 onChange()함수를 input의 onChange={}속성에 걸어 설정하면서, input 값에 변화가 있을 때마다 state 값(=minutes)가 해당 값으로 업데이트되고 이 값은 input value로 보여지게 된다. (input val === state val)

키보드 입력(이벤트 발생)
-> target(=input) value 감지
-> state 값으로 set
-> input value UI로 표기

Final Code

위 코드 플로우를 바탕으로, 호환이 가능한 Converter을 구현한다.

1. 시간 -> 분
2. 분 -> 시간
<script type="text/babel">
  const root = document.getElementById("root")
  function App() {
    // create State
    const [amount, setAmount] = React.useState(0);
    const [flip, setFlip] = React.useState(false);
    const onChange = (e) => {
      // console.log(e.target.value);
      setAmount(e.target.value);
    }
    const reset = () => setAmount(0);
    const onflip = () => {
      reset();
      setFlip(current => !current);
      console.log(flip);
    } // 현재 flip값의 반대 
    return (
      (
        <div>
          <h1 className="title">Converter</h1>
          <div>
            <label htmlFor="min">Minutes </label>
            <input
              id="min"
              placeholder="Minutes"
              type="number"
              value={flip ? amount * 60 : amount}
              // state val === input val
              onChange={onChange}  // onChange: 변화가 있을 때마다 감지하는 func 
              disabled={flip} // == disabled={flip === true}
            // flip일 때 disabled되니까 flip이면 시간입력가능 
            // ==> flip일때는 시간값*60으로 min 인풋창에 보여져야함.
            // ==> 아니라면 amount 그대로 보여져야함
            />
          </div>
          <div>
            <label htmlFor="hrs">Hours </label>
            <input
              id="hrs"
              placeholder="Hours"
              type="number"
              value={flip ? amount : Math.round(amount / 60)}
              onChange={onChange}
              disabled={!flip} // == disabled={flip === false}
            // flip이 false이면 입력불가능
            // flip이 true일 경우, 입력값 그대로 표기,
            // 아니라면 60으로 나누어 표기

            />
          </div>
          <button onClick={reset}>Reset</button>
          <button onClick={onflip}>{flip ? '->Change to *Mins to Hrs*' : '->Change to *Hrs to Mins*'}</button>
        </div>
      )
    )
  }
  ReactDOM.render(<App />, root);
</script>

📌 Check Point

  1. if문 함수로 표현하는 대신 삼항연산자로 간단한 알고리즘 구현
  2. contents를 state로 표현 (ex. button 내용 변경)

Super Converter 만들기

select, option로 선택사항을 추가해보자.

function MinsToHrs() {...}
function KmToMile() {...}
function App() {
    const [index, setIndex] = React.useState('0');
    const onSelect = (e) => setIndex(e.target.value);
    return (
      (
        <div>
          <h1 className="title">Super Converter</h1>
          <select value={index} onChange={onSelect}>
            <option value="0">Minutes / Hours</option>
            <option value="1">km / Mile</option>
          </select>
          {index === '0' ? <MinsToHrs /> : null}
          {index === '1' ? <KmToMile /> : null}
        </div>
      )
    )
  }

📌 Check Point

  1. state를 바꾸면 해당 컴포넌트 - 연계 컴포넌트는 re-rendering 된다. 무조건!
  2. 속성으로 value 를 가질 수 있으면onChange 속성을 붙일 수 있다.
  3. 속성값을 컨트롤해서 로직을 만드는 연습을 하자.

덧붙이는 Code

위의 코드를 참고하여 KM -> MILE Converter를 만들었다.

function KmToMile() {
    const [amount, setAmount] = React.useState(1);
    const [km, setKm] = React.useState(true);
    const onChange = (e) => {
      setAmount(e.target.value)
    };
    const reset = () => setAmount('');
    const onKm = () => {
      reset();
      setKm(cur => !cur) // 이게 바뀌면 disabled에 영향을 주니까.
    }
    return (
      <div>
        <h3>KM to MILE</h3>
        <div>
          <label htmlFor="km">Km </label>
          <input
            type="number"
            id="km"
            value={km ? amount : (amount / 1.609).toFixed(2)}
            onChange={onChange}
            disabled={!km}
          />
        </div>

        <div>
          <label htmlFor="mile">Mile </label>
          <input
            type="number"
            id="mile"
            value={km ? (amount * 1.609).toFixed(2) : amount}
            onChange={onChange}
            disabled={km}
          />
        </div>
        <div>
          <button onClick={onKm}>{km ? 'Change Mile converter' : 'Change Km Converter'}</button>
        </div>
        <div>
          <button onClick={reset}>reset</button>
        </div>
      </div>
    )

Flow

km값을 시작으로, km 모드이면 mile이 disabled
-> km value 입력
-> target value로 amount state 변경
-> km 모드이므로 km칸 amount 그대로 표기,
mile칸 *1.609, 소수점 2자리까지 표기(.toFixed())

-> mode change
-> onKm()발동
-> 입력값 / 계산값 리셋,
km 현재 값이 true 였으므로 false로 변환
-> km === false이므로 km칸 disabled, mile칸 abled
-> mile converter 사용가능


Overall Summary

이 일련의 과정으로 로직을 갖는 컴포넌트를 분리해 생성하는 연습을 했다.

* 컴포넌트  :  App(), MinsToHrs(), KmToMile()

각 로직에 따라 컴포넌트로 독립개체로 분할하면 사용성과 효율이 상승하고, 필요에 따라 재사용도 가능하다. 쉽게 말해 요소를 컨트롤하기 쉬워진다.

 분할 => 정복

여기서 생각해 볼 문제

모든 컴포넌트가 방금 구현한 것처럼 한 페이지에 몰려있다면?
나중에 앱이 고도로 발전해 1억개의 단위환산이 필요하게 된다면, 우리는 1억개의 컴포넌트를 한 페이지에서 관리해야 한다. 이것은 매우 비효율적이다.

컴포넌트는 각각 로직에 따라 분류되어져야 할 것이고, 분리된 컴포넌트들을 잘 연결해 데이터 전달이 용이하도록 만들어야 오류없는 애플리케이션을 구현할 수 있을 것이다.
독립적으로 분류된 컴포넌트를 더 효율적으로 관리하기 위해 필요한 것이 Props이다.
그렇다면 이제 Props를 알아보자.

좋은 웹페이지 즐겨찾기