course/nomadcoder

[ReactJS로 영화 웹 서비스 만들기] State

hjkim0502 2021. 11. 11. 18:14
    • <!DOCTYPE html>
      <html lang="en">
        <body>
          <!-- 위치 지정하기 위해 적는 유일한 html 코드 -->
          <div id="root"></div>
        </body>
        <!-- import React -->
        <script src="https://unpkg.com/react@17.0.2/umd/react.production.min.js"></script>
        <script src="https://unpkg.com/react-dom@17.0.2/umd/react-dom.production.min.js"></script>
        <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
      
        <script type="text/babel">
          const root = document.getElementById("root");
          let counter = 0;
          function countUp() {
            counter = counter + 1;
            // UI에 클릭 수 반영하기 위해 다시 rendering
            // 데이터를 바꿀 때마다 계속 다시 rendering 해야 하므로 좋지 않는 방법
            render();
          }
          function render() {
            ReactDOM.render(<Container />, root);
          }
          const Container = () => (
            <div>
              <h3>Total clicks: {counter}</h3>
              <button onClick={countUp}>click me</button>
            </div>
          );
          render();
        </script>
      </html>
      클릭마다 화면에 반영하는 기능 추가 (순서: render() -> Container() -> 클릭버튼 누르면 countUp() -> render())
    • JSX 환경에서 {}안에 JS코드 삽입 가능
    • react vs vanilla
      react는 모든 것을 다시 render하는 것임에도 오직 바뀐 부분만 업데이트 -> interactive 하게 만들 수 있음
  • 더 간단한 방법
    • <!DOCTYPE html>
      <html lang="en">
        <body>
          <!-- 위치 지정하기 위해 적는 유일한 html 코드 -->
          <div id="root"></div>
        </body>
        <!-- import React -->
        <script src="https://unpkg.com/react@17.0.2/umd/react.production.min.js"></script>
        <script src="https://unpkg.com/react-dom@17.0.2/umd/react-dom.production.min.js"></script>
        <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
      
        <script type="text/babel">
          const root = document.getElementById("root");
      
          function App() {
            // [state, modifier] state는 타겟 데이터
            const [counter, setCounter] = React.useState(0); // -> 리스트, 초기 counter 값 0
            const onClick = () => {
              // setCounter가 counter 데이터를 업데이트하고 렌더링까지 해줌 (component rerender)
              setCounter(counter + 1);
            };
            return (
              <div>
                <h3>Total clicks: {counter}</h3>
                <button onClick={onClick}>click me</button>
              </div>
            );
          }
          ReactDOM.render(<App />, root);
        </script>
      </html>
    •       const onClick = () => {
              // setCounter가 counter 데이터를 업데이트하고 렌더링까지 해줌 (component rerender)
              // setCounter(counter + 1); counter 값이 코드의 다른 부분에서 바뀌어 버그 발생 가능
              // 확실하게 현재 값을 바탕으로 modify하는 코드
              setCounter((current) => current + 1);
            };
      modifier함수에 값을 직접 넣을 수도 있지만, 함수를 넣을 수도 있다
    • // 화살표 함수
      
      // 매개변수 없는 경우
      const func = () => console.log('hi');
      
      // 매개변수 1개
      const func = x => x;
      
      // 매개변수 여러개
      const func = (a, b) => a + b;
      
      // 화살표 이후 여러 줄 일때 {} 사용
      // {} 사용 시 값을 반환할 때 return 필수
      // {} 사용 시 return 쓰지 않으면 undefined 반환
  • 분 -> 시 변환기
    • <!DOCTYPE html>
      <html lang="en">
        <body>
          <!-- 위치 지정하기 위해 적는 유일한 html 코드 -->
          <div id="root"></div>
        </body>
        <!-- import React -->
        <script src="https://unpkg.com/react@17.0.2/umd/react.production.min.js"></script>
        <script src="https://unpkg.com/react-dom@17.0.2/umd/react-dom.production.min.js"></script>
        <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
      
        <script type="text/babel">
          const root = document.getElementById("root");
      
          function App() {
            const [minutes, setMinutes] = React.useState(0);
            // js 처럼 event를 인자로 받아 input 값 저장
            const onChange = (event) => {
              setMinutes(event.target.value);
            };
            const reset = () => setMinutes(0);
            return (
              <div>
                <h1>Super Converter</h1>
                <div>
                  <label htmlFor="minutes">Minutes</label>
                  <input
                    // state와 연결하면 input 태그 밖에서도 value 수정 가능함
                    value={minutes}
                    id="minutes"
                    placeholder="Minutes"
                    type="number"
                    // 데이터 업데이트
                    onChange={onChange}
                  />
                </div>
                <div>
                  <label htmlFor="hours">hours</label>
                  <input
                    value={minutes / 60}
                    id="hours"
                    placeholder="Hours"
                    type="number"
                  />
                </div>
                <button onClick={reset}>Reset</button>
              </div>
            );
          }
          ReactDOM.render(<App />, root);
        </script>
      </html>
    • class 대신 className, for 대신 htmlFor 처럼 다른 용어 사용하기도 함 (js가 선점)
    • 초깃값(0)으로 렌더링 -> input값 바뀌면 onChange() -> minutes 값 업데이트 -> 다시 렌더링
    • onChange property 없으면 input 값 수정 불가 (hours 안바뀜)
  • 시 -> 분 변환 기능 추가
    • <!DOCTYPE html>
      <html lang="en">
        <body>
          <!-- 위치 지정하기 위해 적는 유일한 html 코드 -->
          <div id="root"></div>
        </body>
        <!-- import React -->
        <script src="https://unpkg.com/react@17.0.2/umd/react.production.min.js"></script>
        <script src="https://unpkg.com/react-dom@17.0.2/umd/react-dom.production.min.js"></script>
        <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
      
        <script type="text/babel">
          const root = document.getElementById("root");
      
          function App() {
            const [amount, setAmount] = React.useState(0);
            const [flipped, setFlipped] = React.useState(false);
            // js 처럼 event를 인자로 받아 input 값 저장
            const onChange = (event) => {
              setAmount(event.target.value);
            };
            const reset = () => setAmount(0);
            // !은 negation
            const onFlip = () => {
              reset();
              setFlipped((current) => !current);
            };
            return (
              <div>
                <h1>Super Converter</h1>
                <div>
                  <label htmlFor="minutes">Minutes</label>
                  <input
                    // state와 연결하면 input 태그 밖에서도 value 수정 가능함
                    value={flipped ? amount * 60 : amount}
                    id="minutes"
                    placeholder="Minutes"
                    type="number"
                    // 데이터 업데이트
                    onChange={onChange}
                    disabled={flipped}
                  />
                </div>
                <div>
                  <label htmlFor="hours">Hours</label>
                  <input
                    // if flipped return minutes, else return minutes / 60
                    value={flipped ? amount : amount / 60}
                    id="hours"
                    placeholder="Hours"
                    type="number"
                    onChange={onChange}
                    // flipped가 false면 disabled가 true
                    disabled={!flipped}
                  />
                </div>
                <button onClick={reset}>Reset</button>
                <button onClick={onFlip}>Flip</button>
              </div>
            );
          }
          ReactDOM.render(<App />, root);
        </script>
      </html>
    • flipped가 false면 분->시, true면 시->분
    • hours 값도 받으므로 헷갈리지 않게 amount로 변수명 수정
  • km&mile 변환기 추가
    • <!DOCTYPE html>
      <html lang="en">
        <body>
          <!-- 위치 지정하기 위해 적는 유일한 html 코드 -->
          <div id="root"></div>
        </body>
        <!-- import React -->
        <script src="https://unpkg.com/react@17.0.2/umd/react.production.min.js"></script>
        <script src="https://unpkg.com/react-dom@17.0.2/umd/react-dom.production.min.js"></script>
        <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
      
        <script type="text/babel">
          const root = document.getElementById("root");
      
          function MinutesToHours() {
            const [amount, setAmount] = React.useState(0);
            const [flipped, setFlipped] = React.useState(false);
            // js 처럼 event를 인자로 받아 input 값 저장
            const onChange = (event) => {
              setAmount(event.target.value);
            };
            const reset = () => setAmount(0);
            // !은 negation
            const onFlip = () => {
              reset();
              setFlipped((current) => !current);
            };
            return (
              <div>
                <div>
                  <label htmlFor="minutes">Minutes</label>
                  <input
                    // state와 연결하면 input 태그 밖에서도 value 수정 가능함
                    value={flipped ? amount * 60 : amount}
                    id="minutes"
                    placeholder="Minutes"
                    type="number"
                    // 데이터 업데이트
                    onChange={onChange}
                    disabled={flipped}
                  />
                </div>
                <div>
                  <label htmlFor="hours">Hours</label>
                  <input
                    // if flipped return minutes, else return minutes / 60
                    value={flipped ? amount : amount / 60}
                    id="hours"
                    placeholder="Hours"
                    type="number"
                    onChange={onChange}
                    // flipped가 false면 disabled가 true
                    disabled={!flipped}
                  />
                </div>
                <button onClick={reset}>Reset</button>
                <button onClick={onFlip}>Flip</button>
              </div>
            );
          }
          function KilosToMiles() {
            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 = () => {
              reset();
              setFlipped((current) => !current);
            };
            return (
              <div>
                <div>
                  <label htmlFor="km">km</label>
                  <input
                    value={flipped ? amount * 1.609344 : amount}
                    id="km"
                    placeholder="km"
                    type="number"
                    onChange={onChange}
                    disabled={flipped}
                  />
                </div>
                <div>
                  <label htmlFor="miles">miles</label>
                  <input
                    value={flipped ? amount : amount / 1.609344}
                    id="miles"
                    placeholder="Miles"
                    type="number"
                    onChange={onChange}
                    disabled={!flipped}
                  />
                </div>
                <button onClick={reset}>Reset</button>
                <button onClick={onFlip}>Flip</button>
              </div>
            );
          }
          function App() {
            const [index, setIndex] = React.useState("x");
            const onSelect = (event) => {
              setIndex(event.target.value);
            };
            return (
              <div>
                <h1>Super Converter</h1>
                <select value={index} onChange={onSelect}>
                  <option value="x">Select</option>
                  <option value="0">Minutes & Hours</option>
                  <option value="1">km & miles</option>
                </select>
                <hr />
                {index === "x" ? <h3>select converter</h3> : null}
                {index === "0" ? <MinutesToHours /> : null}
                {index === "1" ? <KilosToMiles /> : null}
              </div>
            );
          }
          ReactDOM.render(<App />, root);
        </script>
      </html>
      변환기들을 각각의 함수로 만들어 사용자의 설정에 따라 App에서 렌더링