#3 REACT REDUX

#3.0 Setup

REACT로 기본 세팅

react, react router dom 설치 & 세팅


#3.1 Connecting the Store

전에 진행한 store, reducer, dispatcher, action 내용 추가

react로 연결하는 과정에서 Provider 사용

  • 코드

    // index.js
    import React from "react";
    import ReactDOM from "react-dom";
    import { Provider } from "react-redux";
    import App from "./components/App";
    import store from "./store"
    
    const root = ReactDOM.createRoot(document.getElementById("root"))
    
    root.render(
        <Provider store={store}>
            <App />
        </Provider>
    )

#3.2 mapStateToProps

Connect & mapStateToProps를 사용해 state를 컴포넌트에 연결하는 과정

connect - return 내용을 컴포넌트의 prop에 추가한다.

mapStateToProps(state, props)

(* Hook - useSelector()로 state를 가져올 수 있음) 참고

mapStateToProps = useSelector = getState state를 가져오는 역할

  • 코드

    // Home.js
    import React, { useState } from "react";
    import { connect } from "react-redux";
    
    function Home({ toDos }) {
      const [text, setText] = useState("");
      function onChange(e) {
        setText(e.target.value);
      }
    
      function onSubmit(e) {
        e.preventDefault();
        setText("");
      }
    
      return (
        <>
          <h1>To Do</h1>
          <form onSubmit={onSubmit}>
            <input type="text" value={text} onChange={onChange} />
            <button>ADD</button>
          </form>
          <ul>{JSON.stringify(toDos)}</ul>
        </>
      );
    }
    
    function mapStateToProps(state) {
      return { toDos: state };
    }
    
    export default connect(mapStateToProps)(Home);

#3.3 mapDispatchToProps

mapDispatchToProps을 사용해 dispatch 기능을 수행한다.

but 최근에는 connect와 mapStateToProps, mapDispatchToProps를 사용하지 않고

Hooks를 사용해 useDispatch, useSelector를 사용한다.

  • 코드

    // Home.js
    import React, { useState } from "react";
    import { connect } from "react-redux";
    import { actionCreators } from "../store";
    
    function Home({ toDos, addToDo }) {
      const [text, setText] = useState("");
      function onChange(e) {
        setText(e.target.value);
      }
    
      function onSubmit(e) {
        e.preventDefault();
        addToDo(text);
        setText("");
      }
    
      return (
        <>
          <h1>To Do</h1>
          <form onSubmit={onSubmit}>
            <input type="text" value={text} onChange={onChange} />
            <button>ADD</button>
          </form>
          <ul>{JSON.stringify(toDos)}</ul>
        </>
      );
    }
    
    function mapStateToProps(state) {
      return { toDos: state };
    }
    
    function mapDispatchToProps(dispatch) {
      return {
        addToDo: (text) => dispatch(actionCreators.addToDo(text))
      };
    }
    
    export default connect(mapStateToProps, mapDispatchToProps)(Home);
  • 수정 코드

    // Home.js
    import React, { useState } from "react";
    import { useDispatch, useSelector } from "react-redux";
    import { addToDo } from "../store"
    
    function Home() {
      const [text, setText] = useState("");
      const toDos = useSelector((state)=>state)
      const dispatch = useDispatch()
    
      function onChange(e) {
        setText(e.target.value);
      }
    
      function onSubmit(e) {
        e.preventDefault();
        dispatch(addToDo(text))
        setText("");
      }
    
      return (
        <>
          <h1>To Do</h1>
          <form onSubmit={onSubmit}>
            <input type="text" value={text} onChange={onChange} />
            <button>ADD</button>
          </form>
          <ul>{JSON.stringify(toDos)}</ul>
        </>
      );
    }
    
    export default Home;

#3.4 Deleting To Do

onClick 함수를 만들어 deleteToDo함수를 디스패치 할 수 있도록 만들었다.

강의 내용이 아닌 useDispatch를 사용해 생각보다 시간이 더 소요됐다.

그래도 막히는 부분을 찾아가면서 해결하니 성장한 기분이 든다.

  • 코드

    // Home.js
    import React, { useState } from "react";
    import { useDispatch, useSelector } from "react-redux";
    import ToDo from "../components/ToDo";
    import { addToDo, deleteToDo } from "../store"
    
    function Home() {
      const [text, setText] = useState("");
      const toDos = useSelector((state)=>state)
    
      const dispatch = useDispatch()
    
      function onChange(e) {
        setText(e.target.value);
      }
    
      function onSubmit(e) {
        e.preventDefault();
        dispatch(addToDo(text))
        setText("");
      }
    
      const onClick = (e) => {
        dispatch(deleteToDo(e))
      }
    
      return (
        <>
          <h1>To Do</h1>
          <form onSubmit={onSubmit}>
            <input type="text" value={text} onChange={onChange} />
            <button>ADD</button>
          </form>
          <ul>
            {toDos.map(toDo => (
                <ToDo {...toDo} id={toDo.id} onClick={onClick} key={toDo.id}  />
            ))}
          </ul>
        </>
      );
    }
    
    export default Home;
    
    // ToDo.js
    import React from "react";
    
    function ToDo({ text, id, onClick }) {
      return (
        <li>
          {text}
          <button id={id}onClick={() => onClick(id)}>❌</button>
        </li>
      );
    }
    
    export default ToDo;

#3.5 Detail Screen

(+ 추가 개념) /id Detail 페이지에서 상태 확인하기

  • 코드

    //Detail.js
    import React from "react";
    import {useSelector} from "react-redux"
    import { useParams } from "react-router-dom";
    
    function Detail() {
        const toDos = useSelector((state) => state);
        const doId = useParams().id;
        const toDoText=toDos.find((todo)=>todo.id === parseInt(doId))
    
      return (
        <>
        <div>{toDoText?.text}</div>
        <div>User ID:{toDoText?.id}</div>
        </>
      )
    }
    
    export default Detail;

#3.6 Introduction

+ LocalStorage에 저장하기 구현

store.js - persistReducer, combineReducers

index.js - PersistGate

참고 참고2 참고3 다른사람완성본 - 나도 CSS까지 적용해보자 !

  • 코드

    // store.js
    import { combineReducers, createStore } from "redux";
    import storage from "redux-persist/lib/storage";
    import { persistReducer } from "redux-persist";
    
    const persistConfig = {
    key:"todo", //localStorage에 저장될 key값
    storage:storage
    };
    
    const ADD = "ADD";
    const DELETE = "DELETE";
    
    export const addToDo = (text) => {
      return {
        type: ADD,
        text,
      };
    };
    
    export const deleteToDo = (id) => {
      return {
        type: DELETE,
        id,
      };
    };
    
    const reducer = (state = [], action) => {
      switch (action.type) {
        case ADD:
          return [{ text: action.text, id: state.length }, ...state];
        case DELETE:
          return state.filter((toDo) => toDo.id !== action.id);
        default:
          return state;
      }
    };
    
    const allReducer = combineReducers({
        reducer
        });
    
    const store = createStore(persistReducer(persistConfig, allReducer));
    
    export default store;
    
    /////////////////////////////////////
    
    // index.js
    import React from "react";
    import { createRoot } from "react-dom/client";
    import { Provider } from "react-redux";
    import App from "./components/App";
    import store from "./store";
    import { persistStore } from "redux-persist";
    import { PersistGate } from "redux-persist/integration/react";
    
    const rootElement = document.getElementById("root");
    const root = createRoot(rootElement);
    const persistor = persistStore(store);
    
    root.render(
      <Provider store={store}>
        <PersistGate loading={null} persistor={persistor}>
          <App />
        </PersistGate>
      </Provider>
    );

Last updated

Was this helpful?