- Single source of truth : store는 단 하나이며, 모든 앱의 상태는 이곳에 보관된다.
- Immutability : 상태는 오로지 읽을 수만 있으며 변경하려면 '모든 상태'가 변경되어야 한다. 재생성시에는 새로운 객체 혹은 새로운 어레이가 생성되어야 한다.
- Pure function : 상태의 변경은 어떠한 사이드 이펙트도 만들지 않아야 한다.
👉 Reducer에서는 상태를 변경하면 안되며, '새로운 상태'를 리턴해야 한다.
👉 변경을 만들기 위해서는 dispatch를 이용해야 한다.
const action1 = {
type: "namespace/getMyData",
payload : {
id: 123
}
};
👉 잘개 쪼개서 작은 상태의 변경을 나타내어 여러 action을 합쳐 복합 형태를 나타내기에 유용함.
const addObj = (id) => {
type: 'namespace/getMyData',
payload: {
id: String(id).slice(1)
}
}
const store = createStore(reducer, initialState);
const Reducer = (state, action) => {
switch (action.type) {
case "namespcae/getMyData":
const obj = {id: action.payload.id}
return {
...state, obj
};
default:
return state;
}
};
function MyApp() {
const dispatch = useDispatch()
return (
<button onClick={
() => dispatch(addObj(1234))
}>Submit</button>
)
}
function MyApp() {
const dispatch = useDispatch()
const obj = useSelector(state => state.obj)
return (
<button onClick={
() => dispatch(addObj(1234))
}>Submit</button>
)
}
⚡ flux : action -> dispatch -> reducer -> store -> selector
👉 action이 들어오면 dispatch는 reducer로 이를 전달하며, reducer는 action type에 따라 새로운 state를 리턴한다. 그러면 이는 store에 저장되며 여기에 저장된 state를 사용하기 위해 selector를 사용한다.
- Middleware : action object가 reducer에 진입하기 전에 동작한다.
- Enhancer : 전체 state의 상태를 중심으로 redux의 동작을 확장한다.
👉 예시로는 Middleware가 있다.
👉 Middleware는 action object가 promise를 리턴하는지 체크한다.
const store = configureStore({
reducer : {
posts: postsReducer,
users: usersReducer
}
})
const addPost = createAction('post/addPost')
addPost({title: 'post 1'})
const postsReducer = createReducer(initState,
builder => {
builder.addCase(addPost, (state, action) => {
state.posts.push(action.payload)
})
}
)
const postsSlice = createSlice({
name:'posts',
initialState,
reducers: {
addPost(state, action) {
state.postsSlice.push(action.payload)
}
}
})
// 사용
const { addPost } = postsSlice.actions
const reducer = postsSlice.reducer
const postsSelector = state => state.posts
const userSelector = state => state.user
const postsByUserIdSelector = createSelector(
postsSelector,
userSelector,
(posts, user) => {
posts.filter(post => post.username == user.username)
}
)
function App() {
return (
<Provider store={store}>
<div>소개글입니다.</div>
</Provider>
);
}
const dispatch = useDispatch();
<Button onClick={() =>
dispatch(changeTheme(theme === "light" ? "dark" : "light"))
}>
function Header() {
const dispatch = useDispatch();
const theme = useSelector((state) => state.theme);
<Button onClick={() =>
dispatch(changeTheme(theme === "light" ? "dark" : "light"))
}>
const addPost = createAsyncThunk('posts/addPost',
async (title) => {
const result = await PostAPI.addPost({ title })
return result.data
}
)
useEffect(() => {
dispatch(addPost("post 1"))
}, [])