React 공부 정리 #3
State with React
- Udemy 강좌의 ‘Section 3: State with React’에 해당하는 내용
- Redux에 대한 자세한 내용은 Redux를 참고
- 한글로 번역된 내용은 Dobbit.Co님의 github을 참고
Redux의 특징
Single Source of Truth
- Redux는 어플리케이션의 state를 위해 단 한개의 store 를 사용하나 하나의 객체 트리를 사용
console.log(store.getState());
{
visibilityFilter: 'SHOW_ALL',
todos: [{
text: 'Consider using Redux',
completed: true,
}, {
text: 'Keep all state in a single tree',
completed: false
}]
}
State is read-only
- 상태를 변화시키는 유일한 방법은 무슨 일이 벌어지는 지를 묘사하는 액션 객체를 전달하는 방법뿐입니다.
store.dispatch({
type: 'COMPLETE_TODO',
index: 1
});
store.dispatch({
type: 'SET_VISIBILITY_FILTER',
filter: 'SHOW_COMPLETED'
});
Changes are made with Pure Functions
- 액션에 의해 상태 트리가 어떻게 변화하는 지를 지정하기 위해 프로그래머는 순수 리듀서를 작성해야합니다.
function visibilityFilter(state = 'SHOW_ALL', action) {
switch (action.type) {
case 'SET_VISIBILITY_FILTER':
return action.filter;
default:
return state;
}
}
function todos(state = [], action) {
switch (action.type) {
case 'ADD_TODO':
return [...state, {
text: action.text,
completed: false
}];
case 'COMPLETE_TODO':
return [
...state.slice(0, action.index),
Object.assign({}, state[action.index], {
completed: true
}),
...state.slice(action.index + 1)
];
default:
return state;
}
}
import { combineReducers, createStore } from 'redux';
let reducer = combineReducers({ visibilityFilter, todos });
let store = createStore(reducer);
- action은 무언가 일어난다는 사실을 기술
- reducer는 그 결과 애플리케이션의 상태가 어떻게 바뀌는지는 기술
- reducer에 인수가 주어지면, 다음 상태를 계산해서 반환해야 하며, 예기치 못한 일, 사이드 이펙트는 없어야 되고, API 호출도 안되며, 변경도 안됨! 오직 계산만 가능
Redux 설정
폴더 구조
|----\src
|----\actions
|---- index.js
|----\components
|---- app.js
|----\reducers
|---- index.js
|---- index.js
|----\style
|---- style.css
|-- index.html
|-- package.json
|-- webpack.config.js
package.json
{
"name": "modern_react_with_redux_study",
"version": "1.0.0",
"description": "[Modern React with Redux](https://www.udemy.com/react-redux/)를 수강하면서 진행한 예제",
"main": "index.js",
"scripts": {
"start": "node ./node_modules/webpack-dev-server/bin/webpack-dev-server.js"
},
"repository": {
"type": "git",
"url": "git+https://github.com/sigmadream/modern_react_with_redux_study.git"
},
"author": "",
"license": "ISC",
"bugs": {
"url": "https://github.com/sigmadream/modern_react_with_redux_study/issues"
},
"homepage": "https://github.com/sigmadream/modern_react_with_redux_study#readme",
"dependencies": {
"babel-core": "^6.11.4",
"babel-loader": "^6.2.4",
"babel-preset-es2015": "^6.9.0",
"babel-preset-react": "^6.11.1",
"babel-preset-stage-1": "^6.5.0",
"react": "^15.3.0",
"react-dom": "^15.3.0",
"react-redux": "^4.4.5",
"redux": "^3.5.2",
"webpack": "^1.13.1",
"webpack-dev-server": "^1.14.1"
}
}
webpack.config.js
module.exports = {
entry: [
'./src/index.js'
],
output: {
path: __dirname,
publicPath: '/',
filename: 'bundle.js'
},
module: {
loaders: [{
exclude: /node_modules/,
loader: 'babel',
query: {
presets: ['react', 'es2015', 'stage-1']
}
}]
},
resolve: {
extensions: ['', '.js', '.jsx']
},
devServer: {
historyApiFallback: true,
contentBase: './'
}
};
‘Hello World!’
- Redux가 적용된 프로젝트의 테스트를 위한 ‘Hello World’ 예제를 실행
src\index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import App from './components/app';
import reducers from './reducers';
const createStoreWithMiddleware = applyMiddleware()(createStore);
ReactDOM.render(
<Provider store={createStoreWithMiddleware(reducers)}>
<App />
</Provider>
, document.querySelector('.container'));
- redux의 미들웨어 객체를 생성
- 미들웨어는 프레임워크가 요청을 받고 응답을 만드는 사이에 놓을 수 있는 코드
- 미들웨어는 액션을 보내는 순간부터 스토어에 도착하는 순간까지 사이에 서드파티 확장을 사용할 수 있는 지점을 제공
reducers\index.js
import { combineReducers } from 'redux';
const rootReducer = combineReducers({
state: (state = {}) => state
});
export default rootReducer;
components\app.js
import React, { Component } from 'react';
export default class App extends Component {
render() {
return (
<div>React simple starter</div>
);
}
}
Array