[노마드코더] 초보자를 위한 리덕스 101 - #3 REACT REDUX

TK·2023년 7월 6일
0
post-thumbnail

🔍3.0 Setup


👩‍💻React-Redux 설치

(23.07기준 v8)

  • 이미 react가 설치되어 있는 상황에 추가
    npm install react-redux
  • react와 처음부터 함께 설치
    npx create-react-app my-app --template redux

👩‍💻react-router-dom 설치

(23.07기준 v6)
npm install react-router-dom


👩‍💻 파일 구조

  • vanilla js

🐇코드 보기

  • index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="Web site created using create-react-app"
    />

    <title>Vanilla Redux</title>
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>
  • index.js
import React from "react";
import { createRoot } from "react-dom/client";
import App from "./components/App";

const rootElement = document.getElementById("root");
const root = createRoot(rootElement);
root.render(<App />);
  • components/App.js
import React from "react";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import Home from "../routes/Home";
import Detail from "../routes/Detail";

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/:id" element={<Detail />} />
      </Routes>
    </BrowserRouter>
  );
}
export default App;

🛠️참고) 강의에서는 v5의 react-router-dom으로 작성되었지만, 나는 v6 기준으로 작성하였다.
강의의 버전을 사용하고 싶다면 npm install react-router-dom@5.1.2를 설치하면 된다.

  • routes/Home.js
import React, { useState } from "react";

function Home() {
  const [text, setText] = useState("");
  function onChange(e) {
    setText(e.target.value);
  }
  function onSubmit(e) {
    e.preventDefault();
    console.log(text);
    setText("");
  }
  return (
    <>
      <h1>To Do</h1>
      <form onSubmit={onSubmit}>
        <input type="text" value={text} onChange={onChange} />
        <button>Add</button>
      </form>
	  <ul></ul>
    </>
  );
}
export default Home;

💻 구현 화면


🔍3.1 Connecting the Store


👩‍💻store 파일 만들기

vanilla JS에서 만든 store파일과 똑같이 만든다.

  • store.js
import { legacy_createStore } from "redux";

const ADD = "ADD";
const DELETE = "DELETE";

const addToDo = (text) => {
  return {
    type: ADD,
    text,
  };
};
const deleteToDo = (id) => {
  return {
    type: DELETE,
    id: parseInt(id),
  };
};

const reducer = (state = [], action) => {
  switch (action.type) {
    case ADD:
      return [{ text: action.text }, ...state];
    case DELETE:
      return state.filter((toDo) => toDo.id !== action.id);
    default:
      return state;
  }
};

const store = legacy_createStore(reducer);

// store(=data)변경사항을 알아차리고 변화가 일어난 부분의 Application을 re-render 하고싶다 => index.js에서 연결
store.subscribe();

export default store;

👩‍💻 이론 배우기

  • Provider : React Redux에는 Provider컴포넌트를 통해 앱의 다른 컴포넌트에서 Redux store를 사용할 수 있다.

  • index.js
    - Provider 추가

import React from "react";
import { createRoot } from "react-dom/client";
import App from "./components/App";
import { Provider } from "react-redux"; // 추가
import store from "./store"; // 추가

const rootElement = document.getElementById("root");
const root = createRoot(rootElement);
root.render(
  <Provider store={store}> // 컴포넌트를 감싼다.
    <App />
  </Provider>
);

🔍3.2 mapStateToProps


👩‍💻이제 뭘 해야하지?

component와 store를 연결시키기

  1. redux state로부터 정보를 가져와야 함 👉 store.dispatch()? store.getState()?
  2. 둘 다 필요, 지금은 getState()기능 먼저 배우기
  3. store에서 Home.js로 정보를 가져와야 함 (ul태그에 데이터를 넣어줘야 하니까!)
  4. 이때 필요한 함수 👉 connect

👩‍💻 이론 배우기

  • connect : 나의 components들을 store에 연결시켜 줌
  • mapStateToProps : 두 종류의 argument와 함께 호출되는 function이다.
    - 첫번째 argument는 Redux store에서 온 state이다.
    - 두번째 argument는 component의 props이다.
    connect는 return한 것을 component의 prop에 추가해준다.

    공식문서

🐇코드 보기

  • routes/Home.js
    - mapStateToProps 추가
import React, { useState } from "react";
import { connect } from "react-redux";

function Home({ toDos }) {
  const [text, setText] = useState("");
  function onChange(e) {
    setText(e.target.value);

		// ...중략...
    
        <input type="text" value={text} onChange={onChange} />
        <button>Add</button>
      </form>
      <ul>{JSON.stringify(toDos)}</ul>
    </>
  );
}

// mapStateToProps: Redux store에서 온 state을 받음
function mapStateToProps(state) {
  return { toDos: state }; // []
}

// connect: Home.js를 store와 연결시킴
export default connect(mapStateToProps)(Home);

💻 구현 화면


💥 대체 Hook : useSelector

connect는 여전히 작동하며 React-Redux 8.x에서 지원된다. 그러나 기본적으로 hooks API를 사용하는 것이 좋다.
더 자세한 내용1
더 자세한 내용2

  • 스토어에 저장된 상태를 참조하는 Hooks 이다. (mapStateToProps 역할과 유사)
  • connect함수를 이용하지 않고 리덕스의 state를 조회할 수 있다.

🐇코드 보기

  • routes/Home.js
    - useSelector 추가
import React, { useState } from "react";
import { useSelector } from "react-redux";
function Home(props) {
  // **React Hook사용**
  // useSelector를 통해 store의 state를 바로 가져옴
  const toDos = useSelector((state) => state);
  const [text, setText] = useState("");
  function onChange(e) {
    setText(e.target.value);
  }
  function onSubmit(e) {
    e.preventDefault();
    console.log(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.3 mapDispatchToProps


dispatch()기능의 mapDispatchToProps

🛠️이 섹션부터 앞으로 react Hooks를 사용하는 코드만 공유한다. mapDispatchToProps함수 활용은 강의 참고

💥 대체 Hook : useDispatch

  • 생성한 action을 useDispatch를 통해 발생시킬 수 있다.
  • 만들어둔 액션생성 함수를 import한다.

🐇코드 보기

  • routes/Home.js
    - useDispatch 추가
import React, { useState } from "react";
import { connect, useDispatch, useSelector } from "react-redux";
import { addToDo } from "../store";
function Home(props) {
  // **React Hook사용**
  // useSelector를 통해 store의 state를 바로 가져옴 (getState기능)
  const toDo = useSelector((state) => state);
  // useDispatch는 mapDispatchToProps 대체: Redux store에서 dispatch 함수에 대한 참조를 반환
  const dispatch = useDispatch();

  const [text, setText] = useState("");
  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(toDo)}</ul>
    </>
  );
}

export default Home;

🔍3.4 Deleting To Do


💻 구현 화면

  • Deleting To Do

🐇코드 보기

  • routes/Home.js
    - ToDo.js 컴포넌트 삽입
// ...생략
import ToDo from "../components/ToDo";
// .. 중략 ..
	  <ul>
        {toDos.map((toDo) => (
          {/* {...toDo}로 모든 정보 보냄 */}
          <ToDo {...toDo} key={toDo.id} />
        ))}
      </ul>
// 생략 ...
  • components/ToDo.js
    - useDispatch 사용
import React from "react";
import { useDispatch } from "react-redux";
import { deleteToDo } from "../store";

function ToDo({ text, id }) {     // text, id 받아옴
  const dispatch = useDispatch();
  const onClick = (e) => {
    const id = e.target.parentElement.id;
    
    // deleteToDo는 store부터 받아옴
    dispatch(deleteToDo(id));
  };

  return (
    <li id={id}>
      {text}
      <button onClick={onClick}>DEL</button>
    </li>
  );
}
export default ToDo;

🔍3.5 Detail Screen


💻 구현 화면

  • Detial Screen

🐇코드 보기

  • routes/Detail.js
    - Detail.js 컴포넌트 삽입
import React from "react";
import { useDispatch, useSelector } from "react-redux";
import { useNavigate, useParams } from "react-router-dom";
import { deleteToDo } from "../store";

function Detail() {
  const id = useParams().id;
  const toDos = useSelector((state) => state);
  const toDo = toDos.find((todo) => todo.id === parseInt(id));
  const dispatch = useDispatch();
  const navigate = useNavigate();

  const handleDel = () => {
    dispatch(deleteToDo(id));
    navigate(-1);
  };
  return (
    <>
      <h1>{toDo?.text}</h1>
      <h5>Created at: {toDo?.id}</h5>
      <button onClick={handleDel}>delete</button>
    </>
  );
}
export default Detail;
  • components/ToDo.js
    - Link 추가
import React from "react";
import { useDispatch } from "react-redux";
import { deleteToDo } from "../store";
import { Link } from "react-router-dom"; // 추가

function ToDo({ text, id }) {
  const dispatch = useDispatch();
  const onClick = (e) => {
    const id = e.target.parentElement.id;
    dispatch(deleteToDo(id));
  };

  return (
    <li id={id}>
      <Link to={`/${id}`}>{text}</Link> {/* 추가 */}
      <button onClick={onClick}>DEL</button>
    </li>
  );
}
export default ToDo;

👩‍💻 이론 배우기

  • Array.prototype.find()

출처 : 노마드코더 - 초보자를 위한 리덕스 101

profile
쉬운게 좋은 FE개발자😺

0개의 댓글

관련 채용 정보