[Redux] Redux API 筆記
Top Level Exports
createStore
createStore(reducer, [preloadedState], [enhancer])
store.getState()
:取得當前所有存在 state 的內容。store.dispatch(action)
:dispatch 的 action 會傳送到 reducer,是唯一用來改變 state 的方式。store.subscribe(listener)
:在每次 action 被 dispatch 的時候都會呼 叫這個 listener。store.replaceReducer(nextReducer)
:
import { createStore } from 'redux';
import rootReducer from './reducers';
// createStore
const store = createStore(rootReducer);
store.getState(); // 取得當前所有存在 state 的內容。
// dispatch action
store.dispatch({
type: 'INCREMENT',
payload: 0,
});
// subscribe(listener):每次 action dispatch 時都會呼叫到這個 callback listener
store.subscribe(() => {
document.body.innerText = store.getState();
});
createStore @ Redux API
原始碼結構
const createStore = (reducer) => {
let state;
let listeners = [];
const getState = () => state;
const dispatch = (action) => {
state = reducer(state, action); // 重要!!
listeners.forEach((l) => l());
};
const subscribe = (listener) => {
listeners.push(listener);
return () => {
listeners = listeners.filter((l) => l !== listener);
};
};
dispatch({});
return { getState, dispatch, subscribe };
};
combineReducer
combineReducers(reducers)
import { combineReducers } from 'redux';
const todoApp = combineReducers({
visibilityFilter,
todos,
});
combineReducer @ Redux API
實際上 combineReducers
是另一個 reducer,而這個 reducer 包了其他原本的 reducers,所以寫成下面這樣是一樣的效果:
/**
* combineReducer 的效果和下面的寫法一樣
* visibilityFilterReducer, todosReducer 都是 reducers
**/
const todoApp = function (state = {}, action) {
const { visibilityFilter, todos } = state;
return {
// 一旦 dispatch() 後,這裡面有寫到的 reducers 都會被呼叫到
visibilityFilter: visibilityFilterReducer(visibilityFilter, action),
todos: todosReducer(todos, action),
};
};
當 store.dispatch()
時,會執行 createStore(<combineReducers>)
時代入的 reducer,在 combineReducers
中,又會去呼叫所有在裡面有寫到的其他 reducers,因此所有的 reducers 都能接到 dispatch 的這個 action
。
也就是說,下面這兩種寫法是一樣的:
// 使用 combineReducers
const reducer = combineReducers({
a: doSomethingWithA, // A Reducer
b: processB, // B Reducer
c: calculateC, // C Reducer
});
// 沒使用 combineReducer
function reducer(state = {}, action) {
const { a, b, c } = state;
return {
a: doSomethingWithA(a, action),
b: processB(b, action),
c: calculateC(c, action),
};
}
bindActionCreators
bindActionCreators(actionCreators, dispatch)
原本需要 dispatch(action)
,但透過 bindActionCreator
後,會變成把 dispatch()
包在原本的 action
中,因此可以直接呼叫該 action 就會發出 dispatch。
用法一:搭配 mapDispatchToProps
使用
原本的寫法:
import { selectBook, deleteBook } from '../actions/index';
const mapDispatchToProps = (dispatch, ownProps) => ({
selectBook: (id) => dispatch(selectBook(id)),
deleteBook: (id) => dispatch(deleteBook(id)),
});
搭配 bindActionCreators
使用(等同於上面的寫法):
import { bindActionCreators } from 'redux';
import { selectBook, deleteBook } from '../actions/index';
const mapDispatchToProps = (dispatch) =>
bindActionCreators(
{
selectBook,
removeBook: deleteBook, // 可以改變 function 的名字
},
dispatch,
);
用法二:變成 boundActionCreators
// someContainer.js
import { bindActionCreators } from 'redux';
import * as TodoActionCreators from './TodoActionCreators';
class TodoListContainer extends Component {
constructor(props) {
super(props);
const { dispatch } = props;
// 使用 bindActionCreators
this.boundActionCreators = bindActionCreators(TodoActionCreators, dispatch);
console.log(this.boundActionCreators);
}
render() {
// 放入綁定好的 boundActionCreators
return <TodoList todos={todos} {...this.boundActionCreators} />;
}
}
bindActionCreators @ Redux API