PJCHENder 未整理筆記

[Redux] Redux API 筆記

2018-09-12

[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)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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

原始碼結構

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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)

1
2
3
4
5
6
import { combineReducers } from 'redux';

const todoApp = combineReducers({
visibilityFilter,
todos
});

combineReducer @ Redux API

實際上 combineReducers 是另一個 reducer,而這個 reducer 包了其他原本的 reducers,所以寫成下面這樣是一樣的效果:

1
2
3
4
5
6
7
8
9
10
11
12
/**
* 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

也就是說,下面這兩種寫法是一樣的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 使用 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 使用

原本的寫法:

1
2
3
4
5
6
import { selectBook, deleteBook } from '../actions/index';

const mapDispatchToProps = (dispatch, ownProps) => ({
selectBook: (id) => dispatch(selectBook(id)),
deleteBook: (id) => dispatch(deleteBook(id)),
});

搭配 bindActionCreators 使用(等同於上面的寫法):

1
2
3
4
5
6
7
8
9
import { bindActionCreators } from 'redux';
import { selectBook, deleteBook } from '../actions/index';

const mapDispatchToProps = (dispatch) =>
bindActionCreators({
selectBook,
removeBook: deleteBook, // 可以改變 function 的名字
}, dispatch
);

用法二:變成 boundActionCreators

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 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

Tags: Redux

掃描二維條碼,分享此文章