Single source of truth : Store는 단 하나이며, 모든 앱의 상태는 이곳에 보관됨
Immutability : 상태는 오로지 읽을 수만 있으며, 변경하려면 모든 상태가 변경되어야 함
Pure function : 상태의 변경은 어떠한 side effect도 만들지 않아야 함
const action1 = {
type: 'namespace/getMyData',
payload: {
id: 123
}
}
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 'namespace/getMyData':
const obj = { id: action.payload.id }
return { ...state, obj }
default:
return state
}
}
const store = createStore(reducer, initialState)
function MyApp() {
const dispatch = useDispatch()
return (
<button onClick={() => dispatch(addObj(1234)}>Submit</button>
)
}
function MyApp() {
const obj = useSelector(state => state.obj)
return (
<div>{JSON.stringify(obj)}</div>
)
}
redux는 middleware, enhancer 등을 이용해 자유롭게 확장하여 사용할 수 있다.
const store = configureStore({
reducer: {
posts: postsReducer,
users: usersReducer
}
})
const addPost = createAction('post/addPost')
addPost({ title: 'post 1' })
/*
{
type: 'post/addPost',
payload: { 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.posts.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)
)
const store = configureStore({
reducer: rootReducer
})
function App() {
return (
<Provider store={store}>
<MyPage />
</Provider>
)
}
const addPost = createAction('addPost')
function MyPage() {
const dispatch = useDispatch()
// dispatch로 redux 내부에 action 전달
const handleClcik = () => dispatch(addPost())
return (
<button onClick={handleClick}>Submit</button>
)
}
function MyPage() {
const posts = useSelector(state => state.posts)
return posts.map(post => <Post {...post} />)
}
fulfilled
, rejected
, pending
3가지 상태에 대해 각각 reducer를 작성)// (action type, async callback)을 인자로 받음
const addPost = createAsyncThunk('posts/addPost', async (title) => {
const result = await PostAPI.addPost({ title })
return result.data
})
// component
useEffect(() => {
dispatch(addPost("post 1"))
}, [])
action type이 주어지면 pending, fulfilled, rejected가 각각 postfix로 붙어 reducer로 들어온다.
(ex: posts/addPost/pending)
createAsyncThunk로 생성된 action creator는 4가지 함수로 구성된다.