React-Redux

์ดˆ์—ฐ2eยท2022๋…„ 11์›” 4์ผ
0

MUTSA_Front.archive

๋ชฉ๋ก ๋ณด๊ธฐ
13/16

6์ฃผ์ฐจ ๊ณผ์ œ: ๋…ธ๋งˆ๋“œ์ฝ”๋” <์ดˆ๋ณด์ž๋ฅผ ์œ„ํ•œ ๋ฆฌ๋•์Šค 101> #3 React Redux & #4 Redux Toolkit ์ˆ˜๊ฐ•




โš™๏ธ Setup

๐Ÿ’ป React-Redux

์„ค์น˜: ํ„ฐ๋ฏธ๋„์— yarn add react-redux ์ž…๋ ฅ

๐Ÿ’ป react-router-dom

์„ค์น˜: ํ„ฐ๋ฏธ๋„์— yarn add react-router-dom ์ž…๋ ฅ

import React from "react";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import Home from '../routes/Home';
import Detail from "../routes/Detail";

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

export default App;

Route๋ฅผ Routes๋กœ ๊ฐ์‹ธ๊ณ  ๊ทธ๊ฑธ ๋˜ Router๋กœ ๊ฐ์‹ธ๋Š” ๋ฐฉ์‹
๊ธฐ๋ณธ์ ์œผ๋กœ๋Š” ์œ„์™€ ๊ฐ™์€ ์ฝ”๋“œ ๊ตฌ์„ฑ์œผ๋กœ ๋Œ์•„๊ฐ„๋‹ค.



๐Ÿ“Œ Store์— ์—ฐ๊ฒฐ

store๋Š” javascript์—์„œ ํ–ˆ๋˜ ๊ฒƒ๊ณผ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ์ž‘์„ฑ!

๋ญ”๊ฐ€ ๋ณ€ํ™”๊ฐ€ ์ผ์–ด๋‚˜๋ฉด ์šฐ๋ฆฌ application์„ ๋‹ค์‹œ renderํ•ด์ฃผ๊ณ  ์‹ถ๋‹ค.
๊ทธ๋Ÿฐ๋ฐ ๋ฆฌ์•กํŠธ๋Š” ๋ณ€ํ™”๊ฐ€ ์ผ์–ด๋‚˜๋Š” ๋ถ€๋ถ„๋งŒ ๋ Œ๋”๋งํ•ด์ค€๋‹ค.

๊ทธ๋ž˜์„œ ์šฐ๋ฆฌ๋Š” react-redux๊ฐ€ ํ•„์š”ํ•˜๋‹ค!
store์˜ ๋ณ€๋™์‚ฌํ•ญ์— ๋Œ€ํ•ด subscribeํ•˜๊ณ  ๊ฑ”๋“ค์ด ๋ฐ”๋€” ๋•Œ ๋ชจ๋“ ๊ฒŒ ๋‹ค์‹œ ๋ Œ๋”๋ง ๋˜๊ฒŒ ํ•ด์ฃผ์ž.



import React from 'react';
import ReactDOM from 'react-dom/client';
import App from "./components/App";
import { Provider } from 'react-redux';
import store from './store';

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

index.js์— ๊ฐ€์„œ ์ด๋ ‡๊ฒŒํ•ด์ฃผ๋ฉด Provider๋ฅผ ํ†ตํ•ด ์•ฑ์˜ ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ์—์„œ Redux store๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.




๐Ÿ’ป mapStateToProps

๐Ÿ“Œ connect


connect: components๋“ค์„ store์— ์—ฐ๊ฒฐ์‹œ์ผœ์ค€๋‹ค.


๐Ÿ“Œ๐Ÿ“Œ mapStateToProps

๋‘ ์ข…๋ฅ˜์˜ argument์™€ ํ•จ๊ป˜ ํ˜ธ์ถœ๋˜๋Š” function

โ–ท ์ฒซ ๋ฒˆ์งธ argument : Redux store์—์„œ ์˜จ state
โ–ท ๋‘ ๋ฒˆ์งธ argument : component์˜ props

	...
function mapStateToProps(state) {
    return { toDos: state };
  }
  
  export default connect(mapStateToProps)(Home);
	...

์š”๋Ÿฐ์‹์œผ๋กœ ํ•ด์ฃผ๋ฉด ์ด์ œ ์šฐ๋ฆฌ๋Š” todo๋ฅผ renderํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๋‹ค~!

๐Ÿ“Œ๐Ÿ“Œ๐Ÿ“Œ mapDispatchToProps

connect ํ•จ์ˆ˜์˜ ๋‘๋ฒˆ์งธ ์ธ์ž.

action์„ reducer ํ•จ์ˆ˜์—๊ฒŒ ๋ณด๋‚ด๋Š” ์—ญํ• ์„ ๊ฐ€์ง„ dispatch๋ฅผ props๋กœ ๋ณด๋‚ผ ์ˆ˜ ์žˆ๋‹ค.

๐Ÿšฉ mapDispatchToProp์˜ ์ธ์ž

โ–ท ์ฒซ ๋ฒˆ์งธ ์ธ์ž dispatch: Redux์˜ store.dispatch()์™€ ๊ฐ™์Œ

โ–ท ๋‘ ๋ฒˆ์งธ ์ธ์ž ownProps: ์ƒ๋žต๊ฐ€๋Šฅ. ์ปดํฌ๋„ŒํŠธ๊ฐ€ ํ˜„์žฌ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๋ชจ๋“  props๋ฅผ ๋ณด์—ฌ์คŒ





๐Ÿ’ป useSelector

connect๋Š” ์—ฌ์ „ํžˆ ์ตœ์‹  ๋ฒ„์ „์—์„œ๋„ ์ž‘๋™ํ•˜์ง€๋งŒ ๊ธฐ๋ณธ์ ์œผ๋กœ hooks useSelector๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋” ์ข‹๋‹ค๊ณ !

๊ณต์‹ ๋ฌธ์„œ์—์„œ๋„ ์ด์ œ connect๋‚˜ mapDispatchToProps๋Š” ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ํ•จ,,

์œ„์˜ ์ฝ”๋“œ๋ฅผ Selector๋ฅผ ์ด์šฉํ•˜์—ฌ ๋ฐ”๊ฟ”๋ณด์ž

๐Ÿ“Œ useSelector

useSelector: selector ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•˜์—ฌ redux store state์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์คŒ

useSelector๋ฅผ ์ด์šฉํ•˜๋ฉด store์˜ state๋ฅผ ๋ฐ”๋กœ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋‹ค.
ex) const todo = useSelector((state)=>state);

๐Ÿ“Œ๐Ÿ“Œ useDispatch

useDispatch: Redux store์—์„œ dispatch ํ•จ์ˆ˜์— ๋Œ€ํ•œ ์ฐธ์กฐ๋ฅผ ๋ฐ˜ํ™˜ (mapDispatchToProps ๋Œ€์‹  ์‚ฌ์šฉ ๊ฐ€๋Šฅ)

ex)

const dispatch = useDispatch();
dispatch(addTodo(text));


โœ๏ธ ์ด ๋ณ€ํ™˜ ์ฝ”๋“œ

import React, { useState } from "react";
import { useSelector,useDispatch } from "react-redux";
import { addToDo } from './../store';

function Home(){
    const [text, setText] = useState("");
    const toDo = useSelector((state)=>state);
    const dispatch = useDispatch();

    function onChange(e){
        setText(e.target.value);
    }

    function onSubmit(e){
        e.preventDefault();
        console.log(text);
        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;





๐Ÿ’ป todo ์‚ญ์ œ ๊ธฐ๋Šฅ


import React from "react";
import { useDispatch } from "react-redux";
import { deleteToDo } from "../store";

function ToDo({ text, id }) {
    const dispatch = useDispatch();

    const onBtnDelete = () => {
        dispatch(deleteToDo(id));
    };

    return (
        <li>
        {text}<button onClick={onBtnDelete}>DEL</button>
        </li>
    );
}

export default ToDo;

import React, { useState } from "react";
import { useSelector,useDispatch } from "react-redux";
import { addToDo } from './../store';
import ToDo from "../components/ToDo";

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();
        console.log(text);
        dispatch(addToDo(text));
        setText("");
    }
    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} key={toDo.id} />
                ))}
            </ul>
        </>
    );
}

export default Home;

toDos๋ฅผ mapํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•˜์—ฌ ์„ค์ •ํ•ด์ฃผ๊ณ  onClick์—์„œ dispatchํ•จ์ˆ˜์— deleteToDo(id)๋ฅผ ๋„ฃ์–ด์„œ ์‚ญ์ œํ•ด์ฃผ์ž. ๊ทธ onClick event๋ฅผ button์— ๋‹ฌ์•„์ฃผ๋ฉด ๋—.

(๊ทผ๋ฐ ๊ฐœ์ธ์ ์œผ๋กœ ๊ฐ•์˜๊ฐ€ ๊ณ„~์† connect, mapDispatchToProps๋ฅผ ์‚ฌ์šฉํ•ด์„œ selector๋ฅผ ์ด์šฉํ•˜์—ฌ ๋ฐ”๊ฟ”์ฃผ๋Š” ๊ทธ ๊ณผ์ •์ด ๋„ˆ๋ฌด๋„ˆ๋ฌด๋„ˆ๋ฌด๋„ˆ๋ฌด ๋ถˆํŽธํ–ˆ๋‹ค,,, ๋ฆฌ๋‰ด์–ผ ์‹œ๊ธ‰,,,,,,)





๐Ÿ’ป Detail ํŽ˜์ด์ง€

๊ฐ ํˆฌ๋‘์— ๋งํฌ๋ฅผ ๊ฑธ์–ด์„œ detail ํŽ˜์ด์ง€๋กœ ๋„˜์–ด๊ฐ€๊ฒŒ ํ•ด์ค„ ๊ฒƒ์ด๋‹ค.

        <li>
            <Link to={`/${id}`}>
                {text}
            </Link>
            <button onClick={onBtnDelete}>DEL</button>
        </li>

์ด๋ ‡๊ฒŒ ํ•ด์ฃผ๋ฉด ๊ฐ id์— ๋”ฐ๋ผ detail ํŽ˜์ด์ง€๋กœ ๋„˜์–ด๊ฐ€๊ฒ ์ง€,,

์ด์ œ params๋ฅผ ๋ฐ›์•„์™€์•ผํ•œ๋‹ค.

id์— Params๋ฅผ ๋ฐ›์•„์˜จ ๋’ค ์ฝ˜์†”์— ์ฐ์–ด๋ณด๋‹ˆ ์ž˜ ์ถœ๋ ฅ๋˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.


import React from "react";
import { connect } from "react-redux";
import { useParams } from "react-router-dom";

function Detail({ toDos }) {
    const myId = useParams().id;
    const toDo = toDos.find((toDo) => toDo.id === parseInt(myId));

    return (
        <>
        	{toDo?.text} - Created at: {toDo?.id}
        </>
    );
}

function mapStateToProps(state) {
    return { toDos: state };
}

export default connect(mapStateToProps)(Detail);

todo์˜ text๋ฅผ ๋ฐ›์•„์™€์„œ ์ถœ๋ ฅํ•˜๊ณ  ๊ทธ ์˜†์— todo์˜ id๊นŒ์ง€ ๊ฐ™์ด ์ถœ๋ ฅํ•˜๋Š” ์ฝ”๋“œ์ด๋‹ค!

find๋Š” testing function์— ๋งŒ์กฑํ•˜๋Š” ์ฒซ๋ฒˆ์งธ ์š”์†Œ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
ํ•ด์„œ ์šฐ๋ฆฌ๋Š” toDo๋ฅผ findํ•ด์ค€ ๊ฒƒ์ด๊ณ  ์ด๋Š” parameter์˜ id์™€ ๊ฐ™์€ ๊ฒƒ์„ ์ฐพ๋Š”๋‹ค.



โœ๏ธ detail page ๊ฒฐ๊ณผ

profile
ํ”„๋ก ํŠธ๋กœ ๋ฉ‹์Ÿ์ด๋˜๊ธฐ ๋Œ€์žฅ์ •,,

0๊ฐœ์˜ ๋Œ“๊ธ€