Redux 공식 홈페이지 따라하기 - Redux 데이터 사용(2)
이전 포스터에서 Redux Toolkit은 createSlice 액션 생성자를 제공한다고 배웠다.
이로인해 코드는 더 짧아졌지만, action.payload 즉 데이터를 정의해야한다.
다행히도 createSlice Reducer를 작성할 때 "prepare callback"함수를 정의한다.
"prepare callback" 함수는 여러 인수를 받는데,
이는 고유 ID와 같은 임의의 값을 생성하고, 액션 객체에 들어갈 값을 결정하는데 필요한 다른 동기 로직을 실행하는데 필요한 "payload" 객체를 반환해야한다.
(반환 객체에는 meta를 포함하는데, meta에 추가 설명값을 추가할 수 있다
만약 error 액션이라면 어떤 종류의 오류를 나타내는지 등..)
createSlice 필드 내부에서 reducers는 { reducer, prepare }와 같은 객체로 정의할 수 있다.
postAdded: {
reducer(state, action){
state.push(action.payload)
},
prepare(title, content){
return {
payload: {
id: nanoid(), // 랜덤 id
title,
content
}
}
}
}
이제 아래의 코드를 실행하여 dispatch할 때 title과 content를 인수로 컴포넌트를 업데이트한다.
const onSavePostClicked = () => {
if (title && content) {
dispatch(postAdded(title, content))
setTitle('')
setContent('')
}
}
사용자 및 게시물
지금까지 우리는 postsSlice.js에 정의된 상태 슬라이스 하나를 가지고 있다.
데이터는 state.posts에 있고 이 모든 구성 욧는 게시물 기능과 관련이 있다.
실제 애플리케이션은 여러 다른 상태 슬라이스와 Redux 로직 및 React 구성 요소에 대한 여러 다른 :"기능 폴더"를 가질 것이다.
따라서 사용자 슬라이스를 추가해보고자 한다.
"사용자"라는 개념은 "게시물"이라는 개념과 다르기때문에 코드와 데이터를 분리해야한다.
따라서 새로운 userSlice.js파일을 만들어야한다.
작업할 데이터가 있도록 초기 항목을 추가한다.
import { createSlice } from '@reduxjs/toolkit'
const initialState = [
{ id: '0', name: 'Tianna Jenkins'},
{ id: '1', name: 'Kevin Grant' } ,
{ id: '2', name: 'Madison Price'}
]
const usersSlice = createSlice({
name: 'users',
initialState,
reducers:{} // 실제로 데이터를 업데이트할 필요가 없기에 빈 객체
})
export default usersSlice.reducer
그 다음, store파일에 usersReducer를 추가해주어야한다.
// store.js
import usersReducer from '../features/users/usersSlice'
export default configureStore({
reducer: {
posts: postsReducer,
users: usersReducer
}
})
게시물 작성자 추가
새 게시물을 추가할 때마다 해당 게시물을 쓴 사용자를 추적해야한다.
실제 앱에서는 state.currentUser에 현재 로그인한 사용장의 정보가 들어가 있기에 게시물을 추가할 때마다 해당 정보를 사용한다.
먼저 사용자 ID를 인수로 받아 들이고 액션 생성자를 업데이트하는 postAdded를 액션에 포함시켜야한다.
(또한 기존 게시물 항목을 업데이트하여 예제 사용자 ID post.user중 하나가 있는 필드 initialState를 갖도록 한다.)
const postsSlice = createSlice({
name: 'posts',
initialState,
reducers: {
postAdded: {
reducer(state, action){
state.push(action.payload)
},
prepare(title, content, userId){
return{
payload: {
id: nanoid(),
title,
content,
user: userId
}
...
이제, useSelector를 통해 드롭다운으로 표시할 수 있다.
그런 다음 선택한 사용자의 ID를 가져와 postAdded 액션 생성자에게 전달한다.
import { useDispatch, userSelector } from 'react-redux'
export const AddPostForm = () => {
const [userId, setUserId] = useState('')
const userss = useSelector(state => state.users)
const onAuthorChanged = e => setUserId(e.target.value)
const onSavePostClicked = () => {
if (title && content){
dispatch(postAdded(title, content, userId))
setTitle('')
setContent('')
}
}
const canSave = Boolean(title) && Boolean(content) && Boolean(userId)
const userOptions = users.map(user => {
<option key={user.id} value={user.id}>
{user.name}
</option>
))
...
<label htmlFor = "postAuthor">Author:</label>
<select id="postAuthor" value = {userId} onChange={onAuthorChanged}>
<option value=""></option>
{usersOptions}
</select
<button type="button" onClick={onSavePostClicked} disabled={!canSave}>
Save Post
</button>
이제 사용자 ID를 prop으로 사용하고 올바른 사용자 객체를 찾고 사용자 이름을 포맷하는 구성요소를 만들 수 있다.
export const PostAuthor = ({ userId }) => {
const author = useSelector(state =>
state.users.find(user => user.id === userId)
}
return <span>by {author ? author.name: "Uknown author"}</span>
}
아하 ! Redux store에서 데이터를 읽어야할 때는 useSelector hook을 사용하면 된다는 사실을 알았다 .
다음은 date에 대한 전역 상태관리를 해보자