2주차 - State 관리
본문 바로가기
항해 중/3주차 리액트 기초반

2주차 - State 관리

by 은돌1113 2021. 11. 15.

1) 단방향 데이터 흐름이란?

: 데이터는 위에서 아래로, 부모에서 자식으로 넘겨줘야 한다는 소리입니다.

 

+ 왜 단방향을 써야 하나요??

: 라이프 사이클과 함께 생각해보기 부모 컴포넌트의 state가 업데이트 되면 자식 컴포넌트도 리렌더링이 일어납니다.

만약 자식 컴포넌트의 state가 바뀐 걸 부모 컴포넌트가 props로 받는다고 생각해봅시다.

그러면 자식 컴포넌트가 업데이트 될 때 부모 컴포넌트도 업데이트 되겠죠?

앗..., 그럼 또 자식 컴포넌트가 리렌더링 될 거구요.

 

무한반복 렌더링이 일어나게 됩니다.!!

 

2) 클래스형 컴포넌트에서 state 관리 - setState()

: 라이프 사이클을 볼 때 잠깐 봤던 setState()!

클래스형 컴포넌트의 state를 업데이트할 때 사용하는 함수입니다.

import React from "react";

class App extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      count: 3, // 숫자넣기!
    };
  }

  componentDidMount() { }

  addNemo = () => {
    // this.setState로 count를 하나 더해줍니다!
    this.setState({ count: this.state.count + 1 });
  };

  removeNemo = () => {
    // 네모 갯수가 0보다 작을 순 없겠죠! if문으로 조건을 걸어줍시다.
    if (this.state.count > 0) {
      // this.setState로 count를 하나 빼줍니다!
      this.setState({ count: this.state.count - 1 });
    } else {
      window.alert('네모가 없어요!');
    }
  };

  render() {
    // 배열을 만듭니다.
    // Array.from()은 배열을 만들고 초기화까지 해주는 내장 함수입니다.
    // Array.from()의 첫번째 파라미터로 {length: 원하는 길이} 객체를,
    // 두번째 파라미터로 원하는 값을 반환하는 콜백함수를 넘겨주면 끝!
    // array의 내장함수 대부분은 콜백 함수에서 (현재값, index넘버)를 인자로 씁니다.
    const nemo_count = Array.from({ length: this.state.count }, (v, i) => i);

    // 콘솔로 만들어진 배열을 확인해봅니다. 숫자가 0부터 순서대로 잘 들어갔나요?
    console.log(nemo_count);

    return (
      <div className="App">
        {nemo_count.map((num, idx) => {
          return (
            <div
              key={idx}
              style={{
                width: "150px",
                height: "150px",
                backgroundColor: "#ddd",
                margin: "10px",
              }}
            >
              nemo
            </div>
          );
        })}

        <div>
          {/* 함수를 호출합니다. 이 클래스 안의 addNemo 함수를 불러오기 때문에 this.addNemo로 표기해요. */}
          <button onClick={this.addNemo}>하나 추가</button>
          <button onClick={this.removeNemo}>하나 빼기</button>
        </div>
      </div>
    );
  }
}

export default App;

 

3) 함수형 컴포넌트에서 state 관리 - useState()

: 이번에는 함수형 컴포넌트에서 어떻게 state를 쓸 수 있는 지 봅시다.

 

함수형 컴포넌트는 클래스형처럼 자체적으로 state를 가지고 있지 않지만, react hooks를 사용하면 state를 가질 수 있습니다!

특히 컴포넌트를 만들고→ state를 쓰는 순서! 뷰 먼저→ 그 다음은 state를 만들고(기본값도 잡아주고!)→ state를 조작하는 무언가를 만들어서→연결한다! 이 순서가 중요해요!

import React from 'react';

function Nemo(props) {

    const [count, setCount] = React.useState(3)
    const nemo_count = Array.from({ length: count }, (v, i) => i);

    const addNemo = ()=>{
        setCount(count + 1);
    }

    const removeNemo = ()=>{
        if(count > 0){
            setCount(count - 1);
        }else{
            alert("네모가 없어요!!")
        }
    }

    return (
        <>
        {
            nemo_count.map((num, idx) => {
                return (
                    <div
                        key={idx}
                        style={{
                            width: "150px",
                            height: "150px",
                            backgroundColor: "#ddd",
                            margin: "10px",
                        }}
                    >
                        nemo
                    </div>
                );
            })
        }

        < div >
        {/* 함수를 호출합니다. 이 클래스 안의 addNemo 함수를 불러오기 때문에 this.addNemo로 표기해요. */ }
            <button onClick={addNemo}> 하나 추가</button >
            <button onClick={removeNemo}>하나 빼기</button>
        </div >
        </>
    );
}

export default Nemo;

퀴즈 - 버킷리스트에 아이템을 추가 해보자!

 

👻 힌트:

  1. 뷰를 먼저 만들어주세요! 텍스트를 입력할 공간과 [추가하기] 버튼을 잊지말고 추가하기!
  2. ref! 잊지 않았죠? text를 가져올 때 써줍니다.
  3. 인풋박스에 입력한 값은 [인풋박스 ref].current.value로 가져올 수 있습니다.
  4. 버킷리스트 컴포넌트는 만질 필요가 없어요. (소근)

-> App.js

import React from "react";
import BucketList from "./BucketList";
import styled from "styled-components";

class App extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      list: ["영화관 가기", "매일 책읽기", "수영 배우기"],
    };

    this.text = React.createRef();
  }

  componentDidMount() {  
  }

  addBucket = () => {
    console.log(this.text.current.value);
    const new_item = this.text.current.value;
    // ... => 스프레드 문법
    // [...this.state.list, 넣고 싶었던 어떤 값]
    this.setState({ list: [...this.state.list, new_item] });
  }

  render() {
    
    return (
      <AppWrap className="App">
        <Container>
          <Title>내 버킷리스트</Title>
          <Line />
          <BucketList list={this.state.list} />
        </Container>

        <InputWrap>
          <input type="text" ref={this.text} />
          <button onClick={this.addBucket}>추가하기</button>
        </InputWrap>
      </AppWrap>
    );
  }
}

const AppWrap = styled.div`
  background-color: #eee;
  height: 100vh;
  width: 100vw;
  display: flex;
  flex-direction: column;
`;

const Container = styled.div`
  background-color: #fff;
  width: 50vw;
  max-width: 350px;
  margin: auto;
  height: 80vh;
  padding: 16px;
  border: 1px solid #ddd;
  border-radius: 5px;
`;

const Title = styled.h1`
  color: slateblue;
  text-align: center;
`;

const Line = styled.hr`
  margin: 16px 0px;
`;


const InputWrap = styled.div`
  background-color: #fff;
  width: 50vw;
  max-width: 350px;
  margin: auto;
  padding: 16px;
  border: 1px solid #ddd;
  border-radius: 5px;
`;

export default App;

-> BucketList.js

import React from "react";
import styled from "styled-components";

const BucketList = ({ list }) => {
  const my_lists = list;
  const my_wrap = React.useRef(null);

  return (
    <div ref={my_wrap}>
      {my_lists.map((list, index) => {
        return <ItemStyle key={index}>{list}</ItemStyle>;
      })}
    </div>
  );
};

const ItemStyle = styled.div`
  padding: 16px;
  margin: 8px;
  background-color: aliceblue;
`;

export default BucketList;

'항해 중 > 3주차 리액트 기초반' 카테고리의 다른 글

3주차 - Event Listener  (0) 2021.11.16
2주차 - 숙제  (0) 2021.11.15
2주차 - Ref(리액트에서 돔요소를 가져오는 방법)  (0) 2021.11.15
2주차 - CSS  (0) 2021.11.15
2주차 - Component  (2) 2021.11.15

댓글