- const TYPE_NAME = "modulename/TYPE_NAME";
export const typeName = (param) =>({
type: TYPE_NAME,
actionData,
})
- const initState = []
- const initState= {}
function reducer(state = initState, action){
switch(action.type){
case TYPENAME:
return {
...state,
data: state.data + 1,
}
case TYPENAME:
return {
...state,
}
default:
return state;
}
}
function reducer(state = initState, action){
switch(action.type){
case TYPENAME:
return state.concat(action.data)
case TYPENAME:
return state.map(
(data)=>data.id === action.id
? console.log("data.id와 action.id는 같다");
: console.log("data.id와 action.id가 다르다");
)
default:
return state;
}
}
- 두개 이상의 모듈이 있을경우 rootReducer가 필요
import { combineReducers } from "redux"
import moduleA from "./moduleA";
import moduleB from "./moduleB";
//Root Reducer생성
const rootReducer = combineReducers({
moduleA,
moduleB,
});
- import { Provider } from "react-redux";
- const store = createStore(rootReducer);
- 확인을 위해서 consloe.log(store.getState())
ReactDOM.render(
//<APP />를 아래와 같이 Provider러 감싼뒤 store를 지정해주면 페이지 어디서나 store를 사용할 수 있다.
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root")
);
- store에 직접 직접 접근하지 않고 props로만 값을 받아온다. 보통 ui를 제작하는 부분이다.
import React from "react";
function Counter({ number, diff, onIncrease, onDecrease, onSetDiff }) {
const onChange = (e) => {
onSetDiff(parseInt(e.target.value), 10);
};
return (
<div>
<h1>{number}</h1>
<div>
<input type="number" value={diff} onChange={onChange} />
<button onClick={onIncrease}>+</button>
<button onClick={onDecrease}>-</button>
</div>
</div>
);
}
export default Counter;
- 리덕스의 있는 상태를 조회하거나 액션을 디스패치할 수 있는 컴포넌트를 의미한다
import React from "react";
import Counter from "../components/Counter";
//상태를 조회하기위한 useSelector dispatch를 위함
import { useSelector, useDispatch } from "react-redux";
//액션 생성함수를 불러와서 디스패치함
import { increase, decrease, setDiff } from "../modules/counter";
function CounterContainer() {
//useSelector를이용해서 해당 state의 값들을 객체향태로 얻어 낸뒤 비구조 할당으로 값을 바로 조회가능하도록만듬
const { number, diff } = useSelector((state) => ({
number: state.counter.number,
diff: state.counter.diff,
}));
const dispatch = useDispatch();
//미리 만들어 놓은 액션생성 함수를 이용하여 디스패치
// 호출되면 액션 객체가 만들어진다.
const onIncrease = () => dispatch(increase());
const onDecrease = () => dispatch(decrease());
const onSetDiff = (diff) => dispatch(setDiff(diff));
//이제 위에서 작업한 내용들을 Conter에 하나하나 잔달하면된다.
return (
<Counter
number={number}
diff={diff}
onIncrease={onIncrease}
onDecrease={onDecrease}
onSetDiff={onSetDiff}
/>
);
}
export default CounterContainer;
- 우리가 만든 Container를 렌더링하자
import React from "react";
import CounterContainer from "./containers/CounterContainer";
function App() {
return <CounterContainer />;
}
export default App;
3개의 컴포넌트들을 하나의 파일에 처리했다.
Todos에 등록폼과 TodoList가있다
TodoList에는 각각의 Todo가 존재하고
TodoItem에는 해당 Todo를 done여부에 따라 보여준다.
컴포넌트의 props가 바뀌지 않았다면 리렌더링을 방지하여 컴포넌트의 리렌더링 성능을 최적화 해 줄 수 있는 React.memo함수로 3개의 컴포넌트를 처리
import React, { useState } from "react";
//Todo를 보여주는 컴포넌트
const TodoItem = React.memo(function TodoItem({ todo, onToggle }) {
return (
<li
style={{
textDecoration: todo.done ? "line-through" : "none",
}}
onClick={() => onToggle(todo.id)}
>
{todo.text}
</li>
);
});
//Todo들의 리스트를 보여주는 컴포넌트
const TodoList = React.memo(function TodoList({ todos, onToggle }) {
return (
<ul>
{todos.map((todo) => (
<TodoItem key={todo.id} todo={todo} onToggle={onToggle} />
))}
</ul>
);
});
//새로운 todo를 생성하기 위한 컴포넌트
function Todos({ todos, onCreate, onToggle }) {
//모든 상태정본를 리덕스에서 관리하는 것은 아님
//필요에 따라 컴포넌트 내부에서 useState로 사용가능
const [text, setText] = useState("");
const onChange = (e) => setText(e.target.value);
const onSubmit = (e) => {
//default로 새로고침이되는데 이것을 적으면 새로고침이 되지 않는다.
e.preventDefault();
//새로고침을 안하는대신 받아온 props로 onCreate을 호출하여 렌더링
onCreate(text);
//onCreate함수 호출이후에는 다시 text를 초기화해준다.
setText("");
};
return (
<div>
<form onSubmit={onSubmit}>
<input value={text} onChange={onChange} placeholder="할일적기" />
<button type="submit">등록</button>
</form>
<TodoList todos={todos} onToggle={onToggle} />
</div>
);
}
//Todos를 내보내준다
export default React.memo(Todos);
위에서 했던 내용과 비슷한 부분이 있다 달라지는 것은 useCallback을 이용한 재사용과 약간의 조건이 생긴 onCreate함수
//함수들을 매벙 렌더랑될 때마다 생성하는것이 아닌 자새용을 위한 useCallback
import React, { useCallback } from "react";
import Todos from "../components/Todos";
import { useSelector, useDispatch } from "react-redux";
import { addTodo, toggleTodo } from "../modules/todos";
function TodoContainer() {
//저번에 한것과 비슷하게 todos를 할당받고 dispatch를 만들어줌
const todos = useSelector((state) => state.todos);
const dispatch = useDispatch();
//아래와 같은 문법을 사용하여 useCallBack을 사용한다
const onCreate = useCallback(
(text) => {
if (text === "") {
alert("값을 입력하세요");
} else {
dispatch(addTodo(text));
}
},
[dispatch]
);
// const onToggle = (id) => dispatch(toggleTodo(id));
const onToggle = useCallback((id) => dispatch(toggleTodo(id)), [dispatch]);
return <Todos todos={todos} onCreate={onCreate} onToggle={onToggle} />;
}
export default TodoContainer;
import React, { useCallback } from "react";
const Afunc = useCallback((param) => dispatch(Bfunc(parm)),[dispatch]);
위에서 만든 Counter앱 밑에 추가로 렌더링 하자 방법은 역시 간단하다
import React from "react";
import CounterContainer from "./containers/CounterContainer";
import Todos from "./containers/TodoContainer";
function App() {
return (
<div>
<CounterContainer />
<hr />
<Todos />
</div>
);
}
export default App;