Daily Front_Minhhk

redux_기본사용, 로거 미들웨어 본문

Study/Redux

redux_기본사용, 로거 미들웨어

Minhhk 2023. 10. 10. 21:01

 

https://d33wubrfki0l68.cloudfront.net/01cc198232551a7e180f4e9e327b5ab22d9d14e7/b33f4/assets/images/reduxdataflowdiagram-49fa8c3968371d9ef6f2a1486bd40a26.gif

 

 

ACTION : 간단한 js 객체..작업의 유형을 지정하는 'type 속성'이 있고, 선택적으로 redux 저장소에 일부 데이터를 보내는데 사용되는 'payload' 속성을 가질 수도 있다.

{type : 'members', memId : 2}
{type : 'USER_NAME', res : {id : 1, name : 'Kim'}}
{type : 'TEXT_LINE', text : '안녕하세요'}

 

 

REDUCER : 상태 변경 사항을 결정하고, 업데이트된 상태를 반환하는 함수. store 내부 상태를 업데이트 한다.

(prev, action) => nextState

 

 

STORE : 객체 저장소 _ 앱의 전체 상태 트리를 보유. 내부 상태를 변경하려면 Action을 전달해야 한다!

 

 


reducers 폴더를 만들어 사용할 reducer를 작성한다.

 

src/reducers/counter.tsx

interface Action {
  type: string;
}

const counter = (state = 0, action: Action) => {
  switch (action.type) {
    case "INCREMENT":
      return state + 1;
    case "DECREMENT":
      return state - 1;

    default:
      return state;
  }
};

export default counter;

 

 

src/reducers/todos.tsx

enum ActionType {
  ADD_TODO = "ADD_TODO",
  DELETE_TODO = "DELETE_TODO",
}

interface Action {
  type: ActionType;
  text: string;
}

const todos = (state = [], action: Action) => {
  switch (action.type) {
    case "ADD_TODO":
      return [...state, action.text];

    default:
      return state;
  }
};

export default todos;

 

두 개의 reducer을 combineReducers 를 이용해 rootReducer 을 만든다.

 

src/reducers/index.ts

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

const rootReducer = combineReducers({
  todos,
  counter,
});

export default rootReducer;

export type RootState = ReturnType<typeof rootReducer>;

 

다음으로  store에 넣어준다.

const store = createStore(rootReducer);

그리고 <Provider >를 통해 store를 전달!!

      <Provider store={store}>
        <App/>
      </Provider>

리듀서 등록 완료!

 

 


 

 

 

useSelector을 통해 store의 값을 꺼내 쓴다.
const todos = useSelector((state) => state.todos )

 

 

useDispatch() 를 통해 action을 전달 해준다.
dispatch({ type: "ADD_TODO", text: todoValue });

 

 

app.tsx

import { ChangeEvent, FormEvent, useState } from "react";
import { useSelector, useDispatch } from "react-redux";
import { RootState } from "./reducers";

type Props = {
  value?: any;
  onIncrement?: () => void;
  onDecrement?: () => void;
};

function App({ value, onIncrement, onDecrement }: Props) {
  const [todoValue, setTodoValue] = useState("");

  // useSelector
  const todos: string[] = useSelector((state: RootState) => state.todos);
  const counter = useSelector((state: RootState) => state.counter);

  // dispatch
  const dispatch = useDispatch();

  const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
    setTodoValue(e.target.value);
  };

  const addTodo = (e: FormEvent<HTMLFormElement>) => {
    e.preventDefault();

    // dispatch
    dispatch({ type: "ADD_TODO", text: todoValue });

    setTodoValue("");
  };

  return (
    <div>
      <p>Clicked : {counter} times</p>
      <button onClick={onIncrement}>+</button>
      <button onClick={onDecrement}>-</button>

      <ul>
        {todos.map((todo, i) => (
          <li key={i}>{todo}</li>
        ))}
      </ul>

      <form onSubmit={addTodo}>
        <input type="text" value={todoValue} onChange={handleChange} />
        <input type="submit" />
      </form>
    </div>
  );
}

export default App;

 

 

index.tsx

import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import { applyMiddleware, createStore } from "redux";
import rootReducer from "./reducers";
import { Provider } from "react-redux";

const root = ReactDOM.createRoot(
  document.getElementById("root") as HTMLElement
);

// logger middleware_
const loggerMiddleware = (store: any) => (next: any) => (action: any) => {
  console.log("store", store);
  console.log("action", action);
  next(action);
};

const middleware = applyMiddleware(loggerMiddleware);
const store = createStore(rootReducer, middleware);

const render = () =>
  root.render(
    <React.StrictMode>
      <Provider store={store}>
        <App
          value={store.getState()}
          onIncrement={() => store.dispatch({ type: "INCREMENT" })}
          onDecrement={() => store.dispatch({ type: "DECREMENT" })}
        />
      </Provider>
    </React.StrictMode>
  );

render();
store.subscribe(render);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

 

 

 


로거 미들웨어

dispatch에 의해 action이 작동 될 때, store & action의 로그를 볼 수있다.

// logger middleware_
const loggerMiddleware = (store: any) => (next: any) => (action: any) => {
  console.log("store", store);
  console.log("action", action);
  next(action);
};

const middleware = applyMiddleware(loggerMiddleware);
const store = createStore(rootReducer, middleware);

 

'Study > Redux' 카테고리의 다른 글

redux_toolkit  (0) 2023.10.12
redux_thunk  (0) 2023.10.11