Redux 0편: 컴포넌트와 상태(state)

이은지·2022년 2월 20일
1

개념을 정확히 정리하려는 의도보다는 "셀프 코드 리뷰 + 지극히 개인적인 관점에서 이해한 개념" 에 가깝다! 원래 배운 걸 나만의 언어로 표현할 수 있어야 그 개념을 아는 거라고 했다. 일단 되는 코드를 짜는 것에 급급했더니 머릿속에 정리가 하나도 안된 기분이라, 더 늦기 전에 작성해본다. 미래의 내가 이 글을 보고 내 코드의 부족함을 지적할 수 있길 바라는 마음에 남겨두는 기록 👏

분명 redux를 정리하려고 한건데... 쓰다보니 컴포넌트랑 상태까지 거슬러 올라가게 됐다.

💜 리액트의 컴포넌트

일단 리액트는 컴포넌트라는 요소들로 이루어져 있다.
그럼 컴포넌트란? 앱을 구성하는 최소한의 단위

마치 한글의 형태소 같은 느낌이다. 자립 형태소처럼 혼자서도 그럴싸한 기능을 잘 해내는 컴포넌트가 있는 반면에, 의존 형태소처럼 다른 컴포넌트와 조합돼서 쓰이는 컴포넌트도 있다. (사실 이건 내가 짜기 나름이다.)

그냥 특정 기능을 하기 위한 코드를 모아놓은 코드 덩어리라고 이해해도 무방하다.


A라는 기능을 구현하고 싶을 때, A를 얼마나 잘게 쪼개서 구현할지는 전적으로 내 선택이다.

잘게 쪼갠다 = 작은 컴포넌트 여러 개를 만들어서 조합한다
쪼개지 않는다 = 그냥 컴포넌트 한 개 안에 모든 기능을 넣는다

이건데, 이걸 얼마나 잘게 쪼갤지는 항상 코드 짤 때 고민되는 부분인 것 같다.
사실 어떻게 짜더라도 확 체감할 수 있을만한 차이는 없기 때문이지. 장기적으로 보면 차이가 크겠지만.

그래도 컴포넌트의 존재 목적이 높은 재사용성과 유지보수의 용이함인 만큼, 그 목적을 해치지 않는 수준에서 적절히 쪼개면 되는 듯하다.


(+) Styled-components와 컴포넌트와 리액트 컴포넌트의 구분

재사용성 있는 컴포넌트는 따로 폴더에 저장해놓고 쓰라는 말을 어디서 듣고서 components 폴더를 아주 남용을 했었다. 심지어 이 과정에서 styled-components의 컴포넌트와 일반적인 리액트 컴포넌트를 구분하지 않고 한 곳에 모아두었다.

이거 다 쓰고 리팩토링 하러 가야겠다.
리액트 컴포넌트는 내용이 있고, styled-component는 서식만 있다.
styled-component는 말그대로 스타일을 입힌 html 태그 일 뿐이다. 예쁜 div. 예쁜 footer.
되게 당연한건데 되는대로 짜다보니 이 차이도 제대로 인지하지 못했네.

  • 리액트 컴포넌트
function() 컴포넌트명 {
	// 각종 state, 함수
    
	return (
    	// 렌더링할 html태그들
    )
}
export default 컴포넌트명
  • styled-components의 컴포넌트
const StyledDiv = styled.div`
	// 해당 div에 입힐 스타일들
    background: blue;
    text-align: center;
`;

export default StyledDiv

💜 리액트의 상태(state)

각 컴포넌트는 상태(state)를 가진다.
상태는 각 컴포넌트 내부에서 선언하고, 각 컴포넌트에서 변경할 수 있다.

✨ 일반 변수랑 state는 뭐가 달라요?
리렌더링의 여부가 다르다. state가 바뀌면 리액트는 해당 state가 포함된 HTML을 자동으로 재렌더링 해준다.
일반 변수는 변경이 발생해도 자동으로 재랜더링되지 않는다.
그러니 바뀌었을 때 UI에 바로바로 반영되어야 할 데이터는 꼭 state로 선언해야 한다.

무튼, 상태가 바뀌면 UI도 바뀐다. 카운터 예제를 생각하면 쉽다.

function Counter() {
	const [number, setNumber] = useState(0);
    // 컴포넌트 내부에서 상태를 선언한다
    // 상태가 바뀌면 화면에 표시되는 숫자도 바뀐다.
    
    const increaseNumber = () => {
    // 컴포넌트 내부에서 상태를 변경한다. 보통 함수를 사용한다.
    }
}

💜 props란

상태는 각 컴포넌트에서 관리하는 게 원칙이다.
근데 다른 컴포넌트의 상태를 가져다 쓰고 싶다면? props를 활용하면 된다.

가장 많이 활용되는 props 패턴은 다음과 같다.
(이 패턴은 컨테이너 컴포넌트-프레젠테이셔널 컴포넌트 패턴이기도 하다.)

export default function ParentComponent() {
  const [name1, setName1] = useState("name1");
  const [name2, setName2] = useState("name2");

  const changeName1 = (name) => {
    setName1(name);
  };
  const changeName2 = (name) => {
    setName2(name);
  };
  return (
    <div className="App">
      <Child1 name={name1} setName1={changeName1} />
      <Child2 name={name2} setName2={changeName2} />
    </div>
  );
}

function Child1({ name, setName1 }) {
  return (
    <>
      <p>{name}</p>
      <button
        onClick={() => {
          setName1("changed name1");
        }}
      >
        change name1
      </button>
    </>
  );
}
function Child2({ name, setName2 }) {
  return (
    <>
      <p>{name}</p>
      <button
        onClick={() => {
          setName2("changed name2");
        }}
      >
        change name2
      </button>
    </>
  );
}

버튼을 클릭하면 이렇게 바뀐다.

codesandbox에서도 확인할 수 있어용!

부모 컴포넌트는 props를 통해 자식 컴포넌트에게 state와, state를 변경할 수 있는 함수를 전달한다.

부모 컴포넌트로부터 전달받은 state변경 함수를 자식 컴포넌트의 특정 UI에 연결한다.
가령 예시를 들자면 이렇다.

  1. 자식 컴포넌트의 버튼 클릭
  2. state변경 함수 가 작동 (onClick으로 연결되어 있던)
  3. 부모 컴포넌트의 state가 변경됨.

부모 컴포넌트: state가 변경됐으므로 리렌더링이 발생
자식 컴포넌트: 부모 컴포넌트에 리렌더링이 발생했으므로 리렌더링이 발생
→ 결과적으로 사용자가 보는 화면도 업데이트됨

이처럼 props를 이용하면 다른 컴포넌트의 상태를 가져다 쓸 수 있다.
단지 가져와서 보여주는 것뿐 아니라 다른 컴포넌트의 상태를 바꿀 수도 있고!

하지만 이 props에는 많은 한계가 존재하는데. . .


드디어 props의 한계까지 진도가 나갔다.
이 내용부터는 다음 글에서 알아보자!!!

다음 글의 내용은 redux의 개념과 redux를 사용하는 이유다.

내 머릿속에 든 거, 내 경험만으로 글 내용 구성할 수 있을 정도로 뭔가 많이 쌓인 거 같아서 기분 좋다!
얼른 얼른 마저 쓰고 리팩토링하고 깃 위키도 써야지

0개의 댓글