λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°

πŸ’¬/γ…γ……γ…Œγ…‹γ…γ…… μ±Œλ¦°μ§€

41일차

πŸ¦₯

41일차

 

Part 11. Redux 둜 μƒνƒœκ΄€λ¦¬ν•˜κΈ°

Ch 1. Redux Basic

 


 

 

Ch 1. Redux Basic

 

 

$ npm i redux

 

단일 μŠ€ν† μ–΄λ‹€!

 

  • 단일 μŠ€ν† μ–΄λ‹€! 
  • [λ§Œλ“€κΈ°] 단일 μŠ€ν† μ–΄ μ‚¬μš© μ€€λΉ„ν•˜κΈ°
    • import redux
    • μ•‘μ…˜μ„ μ •μ˜ν•˜κ³ ,
    • μ•‘μ…˜μ„ μ‚¬μš©ν•˜λŠ”, λ¦¬λ“€μ„œλ₯Ό λ§Œλ“€κ³ ,
    • λ¦¬λ“€μ„œλ“€μ„ ν•©μΉœλ‹€.
    • μ΅œμ’… 합쳐진 λ¦¬λ“€μ„œλ₯Ό 인자둜, 단일 μŠ€ν† μ–΄λ₯Ό λ§Œλ“ λ‹€
  • [μ‚¬μš©ν•˜κΈ°] μ€€λΉ„ν•œ μŠ€ν† μ–΄λ₯Ό λ¦¬μ•‘νŠΈ μ»΄ν¬λ„ŒνŠΈμ—μ„œ μ‚¬μš©ν•˜κΈ°
    • import react-redux
    • connect ν•¨μˆ˜λ₯Ό μ΄μš©ν•΄μ„œ μ»΄ν¬λ„ŒνŠΈμ— μ—°κ²°

 

 

 πŸ”— Action (μ•‘μ…˜) 

 

function μ•‘μ…˜μƒμ„±μž(...args) { return μ•‘μ…˜; }

 

  • μ•‘μ…˜ μƒμ„±μžλ₯Ό 톡해 μ•‘μ…˜μ„ λ§Œλ“€μ–΄ λƒ…λ‹ˆλ‹€.
  • λ§Œλ“€μ–΄λ‚Έ μ•‘μ…˜ 객체λ₯Ό λ¦¬λ•μŠ€ μŠ€ν† μ–΄μ— λ³΄λƒ…λ‹ˆλ‹€.
  • λ¦¬λ•μŠ€ μŠ€ν† μ–΄κ°€ μ•‘μ…˜ 객체λ₯Ό λ°›μœΌλ©΄ μŠ€ν† μ–΄μ˜ μƒνƒœ 값이 λ³€κ²½ λ©λ‹ˆλ‹€. 
  • λ³€κ²½λœ μƒνƒœ 값에 μ˜ν•΄ μƒνƒœλ₯Ό μ΄μš©ν•˜κ³  μžˆλŠ” μ»΄ν¬λ„ŒνŠΈκ°€ λ³€κ²½λ©λ‹ˆλ‹€.
  • μ•‘μ…˜μ€ μŠ€ν† μ–΄μ— λ³΄λ‚΄λŠ” μΌμ’…μ˜ 인풋이라 생각할 수 μžˆμŠ΅λ‹ˆλ‹€.

 

// ./redux/actions.js

export const ADD_TODO = "ADD_TODO";

export function addTodo(todo) {
  return { type: ADD_TODO, todo };
}

 

 

 πŸ”— Reducer (λ¦¬λ“€μ„œ) : Immutable(λΆˆλ³€)

 

function λ¦¬λ“€μ„œ(previousState, action) { 
  return newState;
}

 

// ./redux/reducers.js

import { ADD_TODO } from "./actions";

// state
// ['μ½”λ”©', '점심 λ¨ΉκΈ°']
const initialState = [];

export function todoApp(previousState = initialState, action) {
  // μ΄ˆκΈ°κ°’μ„ μ„€μ •ν•΄μ£ΌλŠ” λΆ€λΆ„
  // if (previousState === undefined) {
  //   return [];
  // }

  if (action.type === ADD_TODO) {
    return [...previousState, action.todo];
  }
  return previousState;
}

 

 

 πŸ”— createStore : μŠ€ν† μ–΄λ₯Ό λ§Œλ“œλŠ” ν•¨μˆ˜

 

const store = createStore(λ¦¬λ“€μ„œ);
createStore<S>(
  reducer: Reducer<S>,
  preloadedState: S,
  enhancer?: StoreEnhancer<S>
): Store<S>;

 

  • store.getState();
    • ν˜„μž¬ state 의 store λ₯Ό κ°€μ Έμ˜¨λ‹€.
  • store.dispatch(μ•‘μ…˜);, store.dispatch(μ•‘μ…˜μƒμ„±μž());
    • action 을 인자둜 λ„£μ–΄μ„œ, state 의 μƒνƒœλ₯Ό λ³€κ²½μ‹œν‚¨λ‹€.
  • const unsubscribe = store.subscribe(() => {});
    • 리턴이 unsubscribe λΌλŠ” 점 !
    • unsubscribe(); ν•˜λ©΄ 제거
    • store 의 변경이 생겼을 λ•Œ ν•¨μˆ˜λ₯Ό μ‹€ν–‰ν•œλ‹€.
  • store.replaceReducer(λ‹€λ₯Έλ¦¬λ“€μ„œ);
    • μ›λž˜ 가지고 있던 λ¦¬λ“€μ„œλ₯Ό λ‹€λ₯Έ λ¦¬λ“€μ„œλ‘œ λ°”κΎΌλ‹€.
    • 잘 μ•ˆ μ“°μž„.

 

// ./redux/store.js

import { createStore } from "redux";
import { todoApp } from "./reducer";

const store = createStore(todoApp);

export default store;
// ./index.js

...
import store from "./redux/store";
import { addTodo } from "./redux/actions";

const unsubscribe = store.subscribe(() => {
  console.log(store.getState());
});

store.dispatch(addTodo("coding"));
store.dispatch(addTodo("read book"));
store.dispatch(addTodo("eat"));
unsubscribe();
store.dispatch(addTodo("coding"));
store.dispatch(addTodo("read book"));
store.dispatch(addTodo("eat"));

...

 

 

 πŸ”— combineReducers 

 

// ./redux/action.js

export const ADD_TODO = "ADD_TODO";
export const COMPLETE_TODO = "COMPLETE_TODO";

// {type: ADD_TODO, text: '할일'}
export function addTodo(text) {
  return {
    type: ADD_TODO,
    text,
  };
}

// {type: COMPLETE_TODO, index: 3}
export function completoTodo(index) {
  return {
    type: COMPLETE_TODO,
    index,
  };
}

export const SHOW_ALL = "SHOW_ALL";
export const SHOW_COMPLETE = "SHOW_COMPLETE";

export function showAll() {
  return { type: SHOW_ALL };
}

export function showComplete() {
  return { type: SHOW_COMPLETE };
}

 

// ./redux/reducers/todos.js

import { ADD_TODO, COMPLETE_TODO } from "../actions";

const initialState = [];

// [{text: 'μ½”λ”©', done: false}, {text: '점심 λ¨ΉκΈ°', done: false}]

export default function todos(previousState = initialState, action) {
  if (action.type === ADD_TODO) {
    return [...previousState, { text: action.text, done: false }];
  }

  if (action.type === COMPLETE_TODO) {
    return previousState.map((todo, index) => {
      if (index === action.index) {
        return { ...todo, done: true };
      }
      return todo;
    });
  }

  return previousState;
}
// ./redux/reducers/filter.js

import { SHOW_ALL, SHOW_COMPLETE } from "../actions";

const initialState = "ALL";

// 'ALL'
export default function filter(previousState = initialState, action) {
  if (action.type === SHOW_COMPLETE) {
    return "COMPLETE";
  }

  if (action.type === SHOW_ALL) {
    return "ALL";
  }

  return previousState;
}
// ./redux/reducers/reducer.js

import { combineReducers } from "redux";
import todos from "./todos";
import filter from "./filter";

const reducer = combineReducers({
  todos,
  filter,
});

export default reducer;

 

// ./redux/store.js

import { createStore } from "redux";
import reducer from "./reducers/reducer";

const store = createStore(reducer);

export default store;
// ./index.js

import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import store from "./redux/store";
import { addTodo, completoTodo, showComplete } from "./redux/actions";

store.subscribe(() => {
  console.log(store.getState());
});

store.dispatch(addTodo("할일"));
store.dispatch(completoTodo(0));
store.dispatch(showComplete(0));

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById("root")
);

 

 

 πŸ”— Redux λ₯Ό React 에 μ—°κ²° 

 

  • react-redux μ•ˆ μ“°κ³  μ—°κ²°ν•˜κΈ° (Context API)
// ./contexts/ReduxContext.js

import { createContext } from "react";

const ReduxContext = createContext();

export default ReduxContext;
// ./index.js

import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import store from "./redux/store";
import ReduxContext from "./contexts/ReduxContext";

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

 

// ./hooks/useReduxState.js

import { useContext, useEffect, useState } from "react";
import ReduxContext from "../contexts/ReduxContext";

export default function useReduxState() {
  const store = useContext(ReduxContext);

  const [state, setState] = useState(store.getState());

  useEffect(() => {
    const unsubscribe = store.subscribe(() => {
      setState(store.getState());
    });

    return () => {
      unsubscribe();
    };
  }, [store]);

  return state;
}
// ./hooks/useReduxDispatch.js

import { useContext } from "react";
import ReduxContext from "../contexts/ReduxContext";

export default function useReduxDispatch() {
  const store = useContext(ReduxContext);

  return store.dispatch;
}

 

// ./components/TodoList.jsx

import useReduxState from "../hooks/useReduxState";
import todos from "../redux/reducers/todos";

export default function TodoList() {
  const state = useReduxState();
  return (
    <ul>
      {state.todos.map((todo) => {
        return <li>{todo.text}</li>;
      })}
    </ul>
  );
}
// ./components/TodoForm.jsx

import { useRef } from "react";
import useReduxDispatch from "../hooks/useReduxDispatch";
import { addTodo } from "../redux/actions";

export default function TodoForm() {
  const inputRef = useRef();
  const dispatch = useReduxDispatch();

  return (
    <div>
      <input ref={inputRef} />
      <button onClick={click}>μΆ”κ°€</button>
    </div>
  );

  function click() {
    dispatch(addTodo(inputRef.current.value));
  }
}
// ./App.js

import logo from "./logo.svg";
import "./App.css";
import { addTodo } from "./redux/actions";
import TodoList from "./components/TodoList";
import TodoForm from "./components/TodoForm";

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <TodoList />
        <TodoForm />
      </header>
    </div>
  );
}

export default App;

 

 

  • react-redux μ“°κ³  μ—°κ²°ν•˜κΈ° (react-redux)
    • Provider μ»΄ν¬λ„ŒνŠΈλ₯Ό μ œκ³΅ν•΄μ€λ‹ˆλ‹€.
    • connect ν•¨μˆ˜λ₯Ό 톡해 "μ»¨ν…Œμ΄λ„ˆ"λ₯Ό λ§Œλ“€μ–΄μ€λ‹ˆλ‹€.
      • μ»¨ν…Œμ΄λ„ˆλŠ” μŠ€ν† μ–΄μ˜ state μ™€ dispatch(μ•‘μ…˜) λ₯Ό μ—°κ²°ν•œ μ»΄ν¬λ„ŒνŠΈμ— props 둜 λ„£μ–΄μ£ΌλŠ” 역할을 ν•©λ‹ˆλ‹€.​
      • κ·Έλ ‡λ‹€λ©΄ ν•„μš”ν•œ 것은 ?
        • μ–΄λ–€ state λ₯Ό μ–΄λ–€ props 에 μ—°κ²°ν•  것인지에 λŒ€ν•œ μ •μ˜
        • μ–΄λ–€ dispatch(μ•‘μ…˜) 을 μ–΄λ–€ props 에 μ—°κ²°ν•  것인지에 λŒ€ν•œ μ •μ˜
        • κ·Έ props λ₯Ό 보낼 μ»΄ν¬λ„ŒνŠΈλ₯Ό μ •μ˜

 

$ npm i react-redux

 

// ./index.js

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

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

 

// ./container/todoistContainer.js

import { useSelector } from "react-redux";
import TodoList from "../components/TodoList";

function TodoListContainer() {
  const todos = useSelector((state) => state.todos);
  return <TodoList todos={todos} />;
}

export default TodoListContainer;
// ./comtianer/TodoFormContainer.js

import { useDispatch } from "react-redux";
import { addTodo } from "../redux/actions";
import TodoForm from "../components/TodoForm";
import { useCallback } from "react";

export default function TodoFormContainer() {
  const dispatch = useDispatch();

  const add = useCallback(
    (text) => {
      dispatch(addTodo(text));
    },
    [dispatch]
  );

  return <TodoForm add={add} />;
}

 

// ./components/TodoList.jsx

export default function TodoList({ todos }) {
  return (
    <ul>
      {todos.map((todo) => {
        return <li>{todo.text}</li>;
      })}
    </ul>
  );
}
// ./components/TodoForm.jsx

import { useRef } from "react";

export default function TodoForm({ add }) {
  const inputRef = useRef();

  return (
    <div>
      <input ref={inputRef} />
      <button onClick={click}>μΆ”κ°€</button>
    </div>
  );

  function click() {
    add(inputRef.current.value);
  }
}
// ./App.js

import logo from "./logo.svg";
import "./App.css";
import TodoListContainer from "./containers/TodoListContainer";
import TodoFormContainer from "./containers/TodoFormContainer";

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <TodoListContainer />
        <TodoFormContainer />
      </header>
    </div>
  );
}

export default App;

 

 

 


 

였늘의 일기

 

 redux react μ—°κ²°ν•˜κΈ° μˆ˜μ—… λ“€μœΌλ©΄μ„œ λΈ”λ‘œκ·Έμ— μ—΄μ‹¬νžˆ μ •λ¦¬ν•˜λ˜ 쀑에 사진을 μ²¨λΆ€ν–ˆλŠ”λ° κ°‘μžκΈ° 엑박이 뜨기 μ‹œμž‘ν–ˆκ³  λ„ˆλ¬΄ λΆˆμ•ˆν–ˆμ§€λ§Œ 손가락을 λ¨ΉμœΌλ©΄μ„œ κΈ°λ‹€λ Έλ‹€............................... 근데 화면이 λ©ˆμ·„λ‹€. λ‚΄ 세상이 λ¬΄λ„ˆμ‘Œλ‹€. 정말 머리가 κ΅³μ—ˆλ‹€. ꡳ은 머리둜 생각 ν•΄λ‚Έκ²Œ μƒˆλ‘œκ³ μΉ¨................................... 맹총이 λ‚΄κ°€ μ—΄μ‹¬νžˆ 기둝 ν–ˆλ˜ 것듀이 λ‹€ 날라가버렸닀. μ§„μ§œ μ•„μ°”ν–ˆκ³  λ„ˆλ¬΄ ν™”κ°€ λ‚˜μ„œ 찐으둜 눈물이 났닀. λ ˆμ•Œ μšΈμ—ˆλ‹€. μ§€κΈˆλ„ λͺ‡μ‹­λΆ„ λ™μ•ˆ μšΈμœΌλ©΄μ„œ λ™λ™λŒ€μ„œ 머리가 μ§€λˆμ§€λˆμš°μ§€λˆν•˜λ‹€. ν•˜ μžλ™ μ €μž₯ κΈ°λŠ₯이 μ—†λŠ” γ…Œγ……γ…Œγ„Ήλ₯Ό μ›λ§ν•˜κΈ° μ‹œμž‘ν–ˆλ‹€. 근데 μ™œ μ•ˆ λ§Œλ“€μ—ˆμ„κΉŒ λ„€μ΄λ²„λŠ” 있던데.............................. γ…Œγ……γ…Œγ„Ήλ₯Ό μ“°λŠ” λ‚΄κ°€ μ›λ§μŠ€λŸ¬μ› κ³  λ…Έμ…˜μœΌλ‘œ λ°”κΏ€κΉŒ μ§„μ§€ν•˜κ²Œ κ³ λ―Όν–ˆλ‹€. κΉƒν—ˆλΈŒ 연동 μ•ˆ ν•΄λ†”μ„œ μ˜›λ‚  μ½”λ“œλŠ” μ—†κ³ ... 희망을 가지고 ctrl Z λ₯Ό λˆŒλŸ¬λ΄€μ§€λ§Œ 이미 μ €μž₯ν•΄μ„œ κ·ΈλŸ°κ°€ (아직도 왠지 λͺ¨λ₯΄κ² λ„€ λΆ„ν•˜λ‹€) 걍 λ’€λ‘œκ°€κΈ°κ°€ μ•ˆ 되던데...................γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ…  λͺ‡μ‹œκ°„λ™μ•ˆ μˆ˜μ—…λ“€μ€κ²Œ λ‚ λΌκ°€λ‹ˆκΉŒγ… γ… γ… γ… γ…  μ™œλƒλ©΄ μ½”λ“œλ„ μ—†κ³  ppt λ³΅λΆ™ν•˜λ € 해도 μˆ˜μ—… λ‚΄μš©μ΄λž‘ ν•΄λ‹Ή μ½”λ“œκ°€ λ‹€λ₯΄λ”라.... 볡슡 ν•˜κ³  싢은데...............................................γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ…  λ‹€μŒμ— ν”„λ‘œμ νŠΈ μ§œλ©΄μ„œ λ‹€μ‹œ 보고 싢은데...γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ… γ…  μ•„ν•˜ν•˜ν•˜γ…ν•˜ν•˜ν•˜ν•³γ…Žν•˜γ…γ… μ§„μ§œ λ‹€μ‹œ 듀을 μ‹œκ°„μ΄ μ—†μ–΄μ„œ.. μ‹œκ°„μ΄ λ„ˆλ¬΄ μ΄‰λ°•ν•œ λ‚ μ΄μ—ˆλ‹€..... μ™œ ν•˜ν•„ 이럴 λ•Œ λ‚˜μ—κ²Œ 이런 μ‹œλ ¨μ΄ μ™”λ‚˜~ 머리λ₯Ό 팍팍팍팍 뜯고 μ‹Άλ‹€. μ‹œκ°„μ΄ μ—†μ§€λ§Œ 여기에 이걸 μ“°κ³  μžˆλŠ” μ΄μœ λŠ” μ§€κΈˆ λ‡Œκ°€ 날라갔닀... 아무 생각이 λ‚˜μ§€ μ•Šκ³  μ˜μ§€κ°€ μ—†λ‹€. λ°₯μ΄λ‚˜ λ¨Ήκ³ ... 금μͺ½μ΄ 보고.. ν•˜ λ‚˜λŠ” μ–΄λ–‘ν•΄~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

 μ§€κΈˆ λ‚¨μ•„μžˆλŠ” μ½”λ“œλž‘ μ˜μƒμ΄λž‘ ppt 긁어 λͺ¨μ•„μ„œ μ–΄λ–»κ²Œ μˆ˜μŠ΅ν•˜κΈ°λŠ” ν–ˆλ‹€. λ‚΄ μ½”λ“œκ°€ μ•„λ‹ˆκ³  주석 처리 ν•œ 것도 μ—†μ–΄μ Έμ„œ μ°μ°ν•˜κΈ°λŠ” ν•˜μ§€λ§Œ 뭐 μ§€λ‚˜κ°„ 일인데 μš°μ§œκ² λƒ μš•ν•œλ‹€κ³  μ§€λ‹ˆκ°€ 찾아와 λ‚΄ μ†Œμ›μ„ λ“€μ–΄μ£Όμ§€λŠ” λͺ»ν•  것이닀... ν›Œν›Œν›Œ λ‚ λž΄λ²„λž΄ 잘 ν–ˆκΈ°λ₯Ό!!!!!!!!!!!!!!! λ‚œ 이제 μ •μ²˜κΈ° 곡뢀 ν•˜λŸ¬ κ°€μ•Όκ² λ‹€ 쿰큼 λ‹€μŒμ—λŠ” ν•œ 챕터할 λ•Œ λ§ˆλ‹€ μ €μž₯ν•˜κ³  λ§ν…Œμ•Ό............................................................................................................................................. κΉƒν—ˆλΈŒλ„......................... ν• κ±°μ•Ό λ‚˜.......................................................................................................................................................... λ‚œ λ„ˆλ¬΄ 슬퍼

일기 끝.

 

~ κ·Έ ν›„ 뒷이야기 ~

 λ‚΄κ°€ μ •λ¦¬ν•œκ²Œ μ•„λ‹ˆμ–΄μ„œ λ†“μΉœ 뢀뢄이 μžˆμ„κΉŒλ΄ μ°μ°ν•˜κΈ°λ„ ν•˜κ³  μ€‘μš”ν•œ λ‚΄μš©μ΄λ‹ˆ λ³΅μŠ΅λ„ ν•  κ²Έ λ‹€μ‹œ μ •λ¦¬ν•˜λŠ” 것도 λ‚˜μ˜μ§€ μ•Šλ‹€κ³  μƒκ°ν•΄μ„œ μ•žμ— 날라간 λΆ€λΆ„λ§Œ λ‹€μ‹œ λ“€μ—ˆλ‹€! 마음이 νŽΈν•˜λ‹€ πŸ˜‡ μœ„μ— μ“΄ κ±° λ³΄λ‹ˆκΉŒ γ„Ήγ…‡ λ©˜λΆ•μ™”λ˜ κ±° κ°™μŒγ…‹γ…‹γ…‹γ…‹γ…‹γ…‹γ…‹γ…‹γ…‹γ…‹γ…‹γ…‹γ…‹γ…‹γ…‹γ…‹γ…‹γ…‹γ…‹γ…‹γ…‹γ…‹γ…‹γ…‹...^^ ν•˜ν•« 였늘의 κ΅ν›ˆ: μ§œμ¦λ‚΄κ³  ν™”λ‚΄κ³  μžμ±…ν•  μ‹œκ°„μ— 재빠λ₯΄κ²Œ λ‹€μ‹œ ν•˜λŠ”κ²Œ μ‹œκ°„(++감정)이 더 μ ˆμ•½λœλ‹€. 끝.

'πŸ’¬ > γ…γ……γ…Œγ…‹γ…γ…… μ±Œλ¦°μ§€' μΉ΄ν…Œκ³ λ¦¬μ˜ λ‹€λ₯Έ κΈ€

43, 44일차  (0) 2022.03.26
42일차  (0) 2022.03.26
useMemo 와 useCallback 은 무엇이 λ‹€λ₯Έ 것인가......  (0) 2022.03.25
40일차  (0) 2022.03.24
39일차  (0) 2022.03.24