Open gincheong opened 3 years ago
// ./action/myAction.js
export const ACTION_TYPE = {
addNumber: '@myApp/ADD_NUMBER'
};
export const addNumber = input => ({
type: ACTION_TYPE.addNumber,
payload: input
});
// ./reducer/myReducer.js
import { ACTION_TYPE } from '../action';
const initialState = {
value: 0
};
export function myReducer (state = initialState, action) {
switch (action.type) {
case ACTION_TYPE.addNumber:
return { ...state, value: state.value + action.payload };
// action의 실행 결과를 가지고 새로운 state를 반환함
default:
return state;
}
}
// ./reducer/index.js
import { combineReducers } from 'redux';
import { myReducer } from './myReducer';
export const rootReducer = combineReducers({
myReducer
});
// 최종적으로 만든 리듀서들을 하나로 합쳐야 함
// ./index.js
...
import { createStore, applyMiddleware, compose } from 'redux';
import { Provider } from 'react-redux';
import { rootReducer } from './reducer';
...
const store = createStore(
rootReducer,
compose(applyMiddleware()) // 필요하다면 여기에 middleware 추가
);
ReactDOM.render(
<Provider store={store}>
...
</Provider>,
...
);
...
// ./components/myComponent.js
...
import { connect } from 'react-redux';
import { addNumber } from '../action';
...
class myComponent extends Component {
...
}
// Redux Store의 state를 조회하여, 어떤 데이터를 컴포넌트의 props로 넣어줄 지 정의함
// 컴포넌트에서 this.props.value로 리듀서에 저장된 값에 접근 가능
const mapStateToProps = state => ({
value: state.myReducer.value
});
// Action을 dispatch하는 함수를 만들어 props에 넣어줌
// 컴포넌트에서 this.props.onIncrease 로 action 실행 가능
const mapDispatchToProps = dispatch => ({
onIncrease: (input) => dispatch(addNumber(input))
});
export default connect(mapStateToProps, mapDispatchToProps)(myComponent);
Action에서 API 통신 등을 하기 위해 비동기 처리가 필요해지면, async, await
키워드를 넣어서 코드를 작성하면 된다고 생각할 수 있는데, 그러면 오류를 발생시키면서 작동하지 않는다.
Error: Actions must be plain objects. Use custom middleware for async actions.
말 그대로, 커스텀 미들웨어를 사용해야 액션에서 비동기 처리를 할 수 있어지는데, 대표적으로 비동기 처리를 위해 redux-thunk
를 많이 사용한다.
npm install redux-thunk
원래 action은 순수 plain object를 반환하던 형태였지만, 이제 비동기 처리를 위해서 dispatch
함수를 인자로 받고 그에 대한 작업 결과를 Promise
객체로 반환하는 함수를 리턴 해야 한다.
export const addNumber = input => ({
type: ACTION_TYPE.addNumber,
payload: input
});
에서
export const addNumber = input => async dispatch => {
await fetch(URL)
.then(async res => {
dispatch({
type: ACTION_TYPE.addNumber,
payload: await res.json()
})
}
)
};
이렇게
그리고 추가로 middleware를 설정하려면, 위의 Store에서 applyMiddleware
에 thunk
를 추가하면 된다.
import thunk from 'redux-thunk';
...
const store = createStore(
rootReducer,
compose(applyMiddleware(thunk)) // 필요하다면 여기에 middleware 추가
);