[React] Redux란?

지냐킴·2022년 8월 2일
0

React

목록 보기
7/20
post-thumbnail

리덕스 정의

전역상태(=데이터) 관리 라이브러리
리덕스는 중앙 state 관리소를 가지고 있으며 모든 state는 이곳에서 생성된다
useState로 생성한 State는 Local State이고, 리덕스에서 생성한 State는 Global State이다.

사용하는 이유


그림처럼 리덕스가 없으면 조부모 컴포넌트에서 손자 컴포넌트로 값을 보내고 싶을때 반드시 부모 컴포넌트를 거쳐야한다 즉, 부모컴포넌트에서는 그 값이 필요가 없지만 손자 컴포넌트로 전달하기 위해 불필요하게 거쳐야한다
그리고 자식 컴포넌트에서 부모 컴포넌트로 값을 보낼 수 없다
리덕스를 사용하면 보-모 관계가 아니여도 되고 중간에 의미 없는 컴포넌트를 거치지 않아도 된다
자식에서 만든 state를 부모 컴포넌트에서도 사용 할 수 있다.
리덕스는 부모도 자식 컴포넌트도 아니다

데이터 관리 흐름도

1.리덕스 스토어를 컴포넌트에 연결한다

=> 컴포넌트들이 스토어에 데이터를 받아가는 걸 구독이라고 한다

2.컴포넌트에서 상태 변화가 필요할 때 액션을 부른다

=> 데이터를 바꾸고 싶은 애한테 바꿔주는 걸 액션을 디스패치 했다
=> 액션 : 나 데이터 수정 할 꺼야 라고 알려주는거

3.리듀서를 통해서 새로운 상태 값을 만든다

4.새 상태값을 스토어에 저장한다
스토어+리듀서 = 리덕스
=> 리덕스에서 리듀서라는 애가 스토어에 저장된 데이터를 실제적으로 바꿔버림
5. 컴포넌트는 새로운 상태값을 받아옴
=> 스토어 데이터가 바껴서 컴포넌트들이 새로운 데이터를 가져오고 리렌더링 됨

리덕스 용어

1. State

리덕스에서 저장 하고 있는 상태값(=데이터)
딕셔너리 형태로 보관한다 ({[key]: value})

2. Action

상태에 변화가 필요할 때(=가지고 있는 데이터를 변경할 때) 발생하는 것
객체이다

// 액션은 객체예요. 이런 식으로 쓰여요. type은 이름같은 거예요! 저희가 정하는 임의의 문자열을 넣습니다.
{type: 'CHANGE_STATE', data: {...}}

3.ActionCrator

액션 생성 함수라고도 부릅니다. 액션을 만들기 위해 사용합니다.

//이름 그대로 함수예요!
const changeState = (new_data) => {
// 액션을 리턴합니다!
	return {
		type: 'CHANGE_STATE',
		data: new_data
	}
}

4.리듀서

리덕스에서 데이터를 실제로바꾸는 곳
액션이 디스패치되는 리듀서는 자동실행 됨
리덕스에 저장된 상태(=데이터)를 변경하는 함수입니다.

// 기본 상태값을 임의로 정해줬어요.
const initialState = {
	name: 'mean0'
}

function reducer(state = initialState, action) {
	switch(action.type){

		// action의 타입마다 케이스문을 걸어주면, 
		// 액션에 따라서 새로운 값을 돌려줍니다!
		case CHANGE_STATE: 
			return {name: 'mean1'};

		default: 
			return false;
	}	
}

5.Store

리듀서의 집합. 스토어 안에 리듀서 포함
리덕스에서 값을 가져오고 액션을 호출하기 위한 내장함수를 포함하고 있다
=> 리듀서를 포함해서 다른 어떤 상태 값을 가져오거나 바꾸거나 하는 내장함수들을 가지고있다.

6. Dispatch

리덕스의 3가지 특징

  1. 스토어는 1개만 쓴다
    => 단일 스토어 규칙을 따른다. 한 프로젝트에 스토어는 하나이다
    단, 리듀서는 여러개 가능
  2. 스토어의 스테이트(데이터)는 오직 액션으로 변경 할 수 있다.
    => 리덕스에 저장된 데이터=상태=state는 읽기 전용이다
  3. 어떤 요청이 와도 리듀서는 같은 동작을 한다
    => 리듀서는 순수한 함수여야한다.

모듈예시

// 1. 액션 타입을 정해줍니다.
const LOAD = "bucket/LOAD"; //로드는 데이터를 주로 서버에서 가져올때 사용한다
const CREATE = "bucket/CREATE"; // 뭔가 생성하는거 = 추가하기 기능 있기에 필요

const initialState = {
  list: ["영화관 가기", "매일 책읽기", "수영 배우기"],
};
// 3.초기 상태값을 만들어준다! 그러니까, 기본 값.
// 초기 상태값을 만들어줍니다.

// 2. Action Creation 
// Create에 대한 객체를 만들기 위한 액션 생성 함수예요.
// creatBucket = (bucket)의 bucket은 어떤 값? 추가할 값 = bucket 데이터! = 새 데이터 = bucket 
  export const createBucket = (bucket) => {
  return { type: CREATE, bucket };
};// 액션 생성 함수는 액션 개체를 리턴해야하기 때문에 딕셔너리 
  // type 으로 어떤 type의 액션인지 알려줘야함 => CREATE 타입의 액션
  //  {bucket:bucket} = {bucket} JS에선 키와 value 값이 같으면 생략가능하다 
 // => {(type이)bucket:bucket}
};
//4. 리듀서
// 실질적으로 store에 들어가 있는 데이터를 변경하는 곳이죠!
export default function reducer(state = initialState, action = {}) {
  // "파라미터(=매개변수)에 = sth" =>기본값을 준다. 
  // state에 값이 안들어온다면 기본값 =initialState를 불러온다 
  // action에 값이 안들어온다면 빈 딕셔너리 호출 
  switch (action.type) {
    case "bucket/CREATE":
     //1.case"액션타입이 뭐가 될꺼야?" => creat action!
      const new_bucket_list = [...state.list, action.bucket];
      // 3.배열에 들어갈 변수 new_bucket_list 
      // 뉴 버킷리스트는 새로운 값을 추개해 놨어야 했다
      // 새로운 값 하나를 원래 거에다가 붙여놨어야 했다
      // 원래 list는 state.list 하고 있어서 스프레드 문법으로 ...state.list해줌
      // 새로 받아온 값=새로운 데이터(bucket)는 액션 개체 안에 들어가있다
      // action 안에 있는 새 bucket 데이터 가져오기 action.bucket 
      
      return { list: new_bucket_list };
      // 5.리턴된 어떤 값이 새로운 스테이트=상태 값이 된다
      //그러면 리턴안에 하나 추가된 리스트, 우리가 입력한 어떤 값을 추가한 배열을 넣어줘야한다 
      // return {list:[]} 이런 형태가 되어야한다 
      
      // 같은 의미
      // {...state.list:[...state.list,action.bucket]}
      // => ...state(모든데이터중에서)list를 [] 데이터로 바꾸겠다
    // [...state.todolist(기본값유지해주고),action.bucket(새 데이터 bucket) 값을 가져오겠다 ]

    default:
      return state;
  }
}

Store 만들기

store과 컴포넌트를 연결할 차례
src/configStore.js 아래에 코드를 입력한다

import { createStore } from "redux";
import { combineReducers } from "redux";
//combineReducers = 리듀서를 묶어주는거
const rootReducer = combineReducers({
  bucket: bucket,
});
const store = createStore(rootReducer);

export default store;

index.js 에 코드를 입력한다

// 우리의 버킷리스트에 리덕스를 주입해줄 프로바이더를 불러옵니다!
import { Provider } from "react-redux";
// 연결할 스토어도 가지고 와요.
import store from "./redux/configStore";

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
    <Provider store={store}>
        <BrowserRouter>
            <App />
        </BrowserRouter>
    </Provider>
);
reportWebVitals();

컴포넌트에서 리덕스 데이터 사용하기

리덕스 훅

// useDispatch는 데이터를 업데이트할 때,
// useSelector는 데이터를 가져올 때 씁니다.
import {useDispatch, useSelector} from "react-redux";
  1. useSelector로 데이터 가져온다
    1) BucketList.js 에서 redux 데이터 가져오기
// redux 훅 중, useSelector를 가져옵니다.
import { useSelector } from "react-redux";

const BucketList = (props) => {
  let history = useHistory();
  //   이 부분은 주석처리!
  //   console.log(props);
  //   const my_lists = props.list;
  // 여기에서 state는 리덕스 스토어가 가진 전체 데이터예요.
  // 우리는 그 중, bucket 안에 들어있는 list를 가져옵니다.
  // useSelector((state)=>state.config파일에서 지정한값 or export한 파일명 => buckt:bucket의 bucket,초기값)
  const my_lists = useSelector((state) => state.bucket.list);
 //   state.bucket.list
 //=> state.config파일에서 지정한값 or export한 파일명=>bucket:bucket의 bucket.초기값)
  return (
    <ListStyle>
      {my_lists.map((list, index) => {
        return (
          <ItemStyle
            className="list_item"
            key={index}
            onClick={() => {
              history.push("/detail");
            }}
          >
            {list}
          </ItemStyle>
        );
      })}
    </ListStyle>
  );
};

2.useDispatch는 데이터를 업데이트
1) App.js에서 사용하기 왜냐하면 추가하기는 app.js에 있으니까

//App.js

// useDispatch를 가져와요!
import {useDispatch} from "react-redux";
// 액션생성함수도 가져오고요!
import { createBucket } from "./redux/modules/bucket";

const dispatch = useDispatch();

const addBucketList = () => {
  //const todo ={
  // id=0;
  //name=n""
    // 스프레드 문법! 기억하고 계신가요? :)
    // 원본 배열 list에 새로운 요소를 추가해주었습니다.
    // 여긴 이제 주석처리!
    // setList([...list, text.current.value]);

    dispatch(createBucket(text.current.value));
  }; // 액션생성함수(creatBucket)
  // = dispatch(creatBucket(todo))
// = dispatch(액션크리에이터(가져오고싶은데이터))

3.useParams 사용
1) 몇 번째 상세에 와있는 지 알기 위해, URL 파라미터를 적용하자

// App.js
<Route exact path="/detail/:index" component={Detail} />

//BucketList.js
      {my_lists.map((list, index) => {
        return (
          <ItemStyle
            className="list_item"
            key={index}
            onClick={() => {
              history.push("/detail/"+index);
            }}
          >
            {list}
          </ItemStyle>
        );
      })`
//Detail.js
// 리액트 패키지를 불러옵니다.
import React from "react";
// 라우터 훅을 불러옵니다.
import {useParams} from "react-router-dom";
// useParams로 인덱스 가져오기
import { useSelector } from "react-redux";
//데이터 가져오기 위해 useSelector import

const Detail = (props) => {
  // 스토어에서 상태값 가져오기
 const params = useParams();
  //1. useParmas 훅으로 index 가져오기 
  // 원래 const index= useParams()였는데 
  // 구분짓기위해 const index를 Params 변수 이름 바꿈
  const bucket_list = useSelector((state) => state.bucket.list);
  // 2.((state중에서)=>state의 bucket 안에 있는 list를 가져오라고 선택 
  const bucket_index = params.index;
  // 3.const index= useParams()라고 쓰면 
  // const bucket_index = index.index 라고 써야함 헷갈리쥬
 //	bucket_list의 찐 index는 
 // const bucket_index = params.index로 가져옴 
  return <h1>{bucket_list[bucket_index]}</h1>;
// bucket_list의 bucket_index를 가져옴 
};

export default Detail;

profile
코린이일기

0개의 댓글