리액트 redux 개념정리

태민·2022년 11월 16일
0

리덕스를 쓰기위해서 리덕스를 설치해야한다

react redux를 웹에서 검색해서 설치하면 된다

다른사람들이 짜놓은 redux개념을 찾아볼 필요가있다

reducer는 액션을 줄인다는 것이다

필요한 액션을 줄인다

줄여서 데이터를 변경하면 state가 변경되고

그게 변경되면 리액트는 동기화가 된다

액션을 주면 스토어를 바라보고 있는 모든 ui가 변경된다

우선 리덕스를 설치해보자

나는 yarn을 사용하니까

yarn add react-redux 를 터미널에 입력해주면된다

설치가 완료되었다는 가정하에 정리를 시작하겠다

App.js로 가서 일단 구조를 짜보자

다 지운상태로 div 안에 최상단화면이라고 h1태그로 표시해주고

src폴더안에 components폴더를 만들고

그 폴더안에 Top.js와 Bottom.js를 만들어주자

rsc로 두 파일 모두 초기세팅해준다

app.css 파일에가서

.container{
    height: 700px;
    border: 2px solid black;
}

.sub_container {
    height: 250px;
    border: 2px solid black;
}

div{
    padding: 10px;
    margin: 10px;
}

이렇게 적어서 전체 컨테이너와 서브 컨테이너를 구분해주고

해당코드를 App.js에는 컨테이너클래스를 부여하고

탑과 바텀 js파일 최초 div에는 sub컨테이너를 부여해주고

탑과 바텀도 hi태그로 알아볼수있게 탑,바텀 이라고 명시해주자

App.js 와 탑 바텀 모두 import로 css 파일을 넣어주자

App.js에 이런식으로 임포트해주고

탑과 바텀에서 css파일을 임포트 할 경우에는 ./ 이 아니라 ../ 으로 해줘야한다

그 이유는 같은 폴더가 아닌 컴포넌트라는 폴더에 있기 때문이다

./ 은 같은 폴더내에서만 사용가능하다

자 이제 bottom으로 가서 증가라는 버튼을 하나 간단하게 만들자

top에는 번호:1 이라고 적어주자

이렇게 나오도록 해주고

state를 app.js에 만드는데

const [number,setNumber]=useState(1);

이렇게 만들어주자

그리고 해당 데이터를 Top에 던져주자

<Top number={number}/>

이렇게 던진것을 탑에서는 props로 받아야한다


const Top = (props) => {

    const{number}=props;

    return (
        <div className={"sub_container"}>
            <h1>Top</h1>
            번호 : {number}
        </div>
    );
};

export default Top;

이런식으로()안에 props를 적어줌으로써

받을 수 있고

아래에 번호 : {number}로 표기해서

번호를 적어주자

바텀에 setNumber를 보내지 않아야한다

보내버리면 거기서 더하기 빼기 모두 가능하기때문에

app.js안에서 함수를 하나 만들자


const addNumber=()=>{
    setNumber(number+1);

}

이렇게 만들어주고


<Bottom addNumber={addNumber}/>

이렇게 함수를 던져주자

이전에는 쉽게 하기 위해서 setNumber자체를 넘겼지만

이렇게 함수 형태로 만들어서 던지면 해당 함수는 증가밖에 할 수 없어서

권한에 제한을 둘 수 있다

인터페이스 개념으로 넘겨야 좋다

넘겼으니 바텀에서 받아야한다


import React from 'react';
import '../App.css';

const Bottom = (props) => {

    const {addNumber} = props;

    return (
        <div className={"sub_container"}>
            <h1>Bottom</h1>
            <button onClick={addNumber}>증가</button>
        </div>
    );
};

export default Bottom;

이렇게 () 안에 props로 받아주고

아래에서 선언을 해준다

그리고 onClick이벤트를 통해서 그 버튼을 눌렀을 때 증가가 되도록 해주면 된다

이제 증가 버튼을 누르면 바텀페이지에서 버튼을 눌러도 탑에 있는 숫자가 컨트롤 되는 것을 볼 수 있다

부모가 모든것을 관리하기 때문에 가능한 일이다

바텀에는 함수를 탑에는 상태를 넘겼기 때문에 가능하지만

만약 뿌리가 20개 200개가 되면 계속 던지고 또 던지고 무한반복해야하기 때문에 너무 불편하다

그래서 우리는 스토어라는 것을 만들어줘야한다

src로 돌아가서

store.js라는 파일을 만들고


//액션을 만들자

export const increase = ()=> ({type:"INCREMENT"});
export const decrease = ()=> ({type:"DECREMENT"});


// 상태를 만들자 초기상태!

const initstate = {
    number:0,

}

// reducer를 만들자
//액션의 결과를 걸러내는 것이 reducer다


const reducer = (state=initstate, action)=>{

    switch (action.type){
        case "INCREMENT":
            return {number: state.number+1} // return되면 그걸 호출한 쪽에서 받는 것이 아니라
        // return 되는 순간 ui 변경만 된다 상태만 변경하지 받는 것이 아니다
        case "DECREMENT":
            return {number: state.number-1}
        default:
            return state;
    }
}


export default reducer;

이렇게작성을 해주는데

원하는 액션을 먼저 만드는데

증가와 감소를 만들어주면 된다

그리고 초기상태를 정해주는데 0으로 정해주면된다

그리고 나서 reducer를 만드는데

실행되면 초기상태가 나오고 그다음 액션을 받는다

액션의 타입이 증가이면?

초기상태에서 1을 더해서 값을 받고

액션의 타입이 감소이면?

초기상태에서 1을 뺀 값을 받고

둘다 아니라면?

그냥 상태값 0을 받는다

아직 제대로 이해되지 않지만 적어가면서 계속 공부해서 이해를 꼭 해야겠다!

가장 하단에 export default라고 써준 이유는

index.js파일을 열어서

`

const store = createStoreHook(reducer);
`

이렇게 임포트를 해주기 위해서 꼭 써줘야하기 때문이다

그렇지 않으면 이렇게 임포트해서 사용할 수 없다

기존으 방식과는 사뭇 다르지만

store를 임포트할 때 hook안에 기본으로 제공해주는 createStoreHook을 통해서 괄호안에 reducer를 적어서 이용해주면 된다

import reducer from "./store";
이렇게 임포트가 되는데 디폴트라 중괄호가 없이 임포트된다

이제 이 스토어를 모든 앱에서 쓸수있게해줘야한다

<Provider store={store()}>
<App />
</Provider>

이렇게 감싸줘야만 모든 파일에서 쓸 수 있게 된다

어디서든지! 이제 스토어를 쓸 수 있게 되었다! 얏호

지금 우리가 쓰는 것이 react hooks인데

잘 만들어진 것을 그대로 사용할 수 있다

아직 내가 이런걸 설계할 레벨이 아니기때문에 리액트 훅스를 이용해서 리덕스를 사용해보자

다시 App.js로 가서

기존에 만들어뒀던


const [number,setNumber]=useState(1);


const addNumber=()=>{
    setNumber(number+1);

}

이 코드는 더이상 필요가 없으니 지워준다

그말은 즉 이제 데이터를 따로 넘길 필요가 없다

그래서 넘겨줬던 것들도 다 지워서

  return (
        <div className={"container"}>
        <h1>최상단 화면</h1>
            <Top/>
            <Bottom/>
        </div>
    );
}

이렇게 만들어준다

상태는 현재 스토어가 다 관리하고있다

이제 탑으로가서

import React from 'react';
import '../App.css';

const Top = () => {

    return (
        <div className={"sub_container"}>
            <h1>Top</h1>
            번호 :
        </div>
    );
};

export default Top;

props로 받았던 것들 모두 지워주고

번호 옆에 적혀있던 받아온 데이터도 지워주고

전부 지워준다

바텀에가서도 똑같이 다 지워준다

이제 넘긴건 하나도 없게됬다

탑에가서 리액트 훅스를 사용해보자


const number = useSelector((store)=>store.number);

이렇게 useSelector를 사용해서 store에 바로 접근해서


const initstate = {
    number:0,

}

이렇게 스토어에 적어뒀던 0이라는 넘버를 그대로 가져올 수 있다

여기까지 하고 저장했는데 1시간동안 찾아보고

할 수 있는 구글링을 다 해봐도 도저히 알 수 없는 에러가

자꾸 생겼다

그래서 결국 보고있던 자료에서 제공하는

코드를 붙여넣었더니?

정상적으로 실행이 된다

이유를 알고 싶은데 이유를 알 수 없는게 너무 속상하다

index.js파일을 전부 지우고

자료에서 제공하는 코드로 변경하니까
정상작동하는 것을 확인 할 수 있었다

아래는 붙여넣은 코드 전문이다

import React from "react";
import ReactDOM from "react-dom";
import { Provider } from "react-redux";
import { createStore } from "redux";
import App from "./App";
import reducer from "./store";

const store = createStore(reducer);

ReactDOM.render(
    <React.StrictMode>
        <Provider store={store}>
            <App />
        </Provider>
    </React.StrictMode>,
    document.getElementById("root")
);

0이라고하니 조금 그래서 1로 수정해주고

재출력했다

정상적으로 출력되는 것을 확인할 수 있었다

이제 바텀으로가서 버튼을 눌렀을 때 증가되도록 해주면 성공!

바텀으로 가서

dispatcher를 이용하기위해 함수를 하나 만든다

const dispatcher= useDispatch();
이렇게 함수를 만들어주고

 return (
        <div className={"sub_container"}>
            <h1>Bottom</h1>
            <button onClick={dispatcher(increase())}>증가</button>
        </div>
    );
};

export default Bottom;

이렇게 작성하고 실행했더니

이렇게 버튼은 눌리지도 않고 숫자는 1에서 자동으로 3이 되어있다

이게 무슨일인가?

다시보니까 버튼에서 함수를 실행해버렸다

즉 버튼을 누르지 않아도 자동으로 실행이 되버리는 것이다

() 를 넣으면 자동으로 함수자체가 클릭전에 이미 실행되어버린다

그래서 우리는 이 코드를

<button onClick={()=>dispatcher(increase())}>증가</button>
이렇게 수정해줘야한다

그러면 이제 버튼 클릭 시 번호가 증가하도록 구현이 완료되었다!

하지만 계속해서 에러 1개가 나오는데 나중에 꼭 잡아야겠다..

이 에러를 마주하기 싫으면 원래 코드로 돌리면 되고

원래 코드로 돌리면 또 화면이 안나오고

나에게는 에러를 마주하는게 아직도 큰 산처럼 느껴진다

이제 감소버튼도 만들어보자

<button onClick={()=>dispatcher(decrease())}>감소</button>

이렇게 적어주고 import해주면!

이렇게 감소 증가 모두 구현을 완료하였다 !

증가를 누르면 이름도 같이 보내줄 수 있도록 하려면 어떻게 해야할까?

스토어로가서

const initstate = {
    username:"",
    number:1,

};

이렇게 유저네임을 만들고 공백으로 준다

export const increase = (username)=> ({type:"INCREMENT",payload:username});

괄호안에 유저네임을 담고 콤마, 를 주고 payload라고 써줬는데

내 마음대로 지어주면 된다 body라고 정해도 무방함

그 안에 username을 담아준다


const reducer = (state=initstate, action)=>{

    switch (action.type){
        case "INCREMENT":
            return {number: state.number+1, username: action.payload}; // return되면 그걸 호출한 쪽에서 받는 것이 아니라
        // return 되는 순간 ui 변경만 된다 상태만 변경하지 받는 것이 아니다
        case "DECREMENT":
            return {number: state.number-1};
        default:
            return state;
    }
}

이렇게 리턴값안에 , 콤마를 주고 유저네임을 액션 Payload로 줘서

증가를 눌렀을 때 반환하는 것을 위에 액션에서 넣은 값을 받아주도록 설정해주고

바텀으로 가서

버튼을

<button onClick={()=>dispatcher(increase("cos"))}>증가</button>

이렇게 수정해주고 증가할 경우 "cos"라는 이름으로 수정되도록 변경해주고 저장하고

실행하면!

증가를 누르면 cos라는 이름이 나오고

감소를 누르면 다시 사라지게 되었다

출력해서 보여주기위해 마지막으로 탑으로가서

import React from 'react';
import '../App.css';
import {useSelector} from "react-redux";



const Top = () => {

    const {number,username} = useSelector((store)=>store);


    return (
        <div className={"sub_container"}>
            <h1>Top</h1>
            번호 : {number}
            이름 : {username}
        </div>
    );
};

export default Top;

이렇게 store.number였던것을 그냥 스토어로 수정하고 앞에 유저네임도 같이 넣어준다

그리고 아래에 이름: {username}이렇게 적어주면

정상적으로 잘 출력되는 것을 볼 수 있다

여기서 증가르 누르면!

이름에 코스가 들어오는 것을 확인할 수 있다

리덕스는 개념파악이 어려우니까 계속해서 실습하면서 내가 이해할 수 있을 지점까지

공부해야겠다

이상 끝!

profile
몰입이 즐거운 개발자

0개의 댓글