Ref: Redux 入門教程(三):React-Redux 的用法html
使用 React-Redux,須要掌握額外的 API,而且要遵照它的組件拆分規範。react
React-Redux 將全部組件分紅兩大類:git
若是一個組件既有 UI 又有業務邏輯,那怎麼辦?github
將它拆分紅下面的結構:redux
* 外面是一個容器組件, ----> 前者負責與外部的通訊,將數據傳給後者 ----> 由 React-Redux 自動生成閉包
* 裏面包了一個UI 組件。 ----> 後者渲染出視圖 ----> 由用戶提供框架
connect
方法,用於從 UI 組件生成容器組件。connect
的意思,就是將這兩種組件連起來。less
import { connect } from 'react-redux'
const VisibleTodoList【容器組件】 = connect(mapStateToProps, mapDispatchToProps)(TodoList【UI組件】)
(1) 一個頁面可能會有十個state,使用connect讓咱們只關注當前有使用的幾個。ide
(2) 尾部的參數的意思:由於返回的是一個帶參數的func,參見: js 用閉包實現 curry化函數
創建一個從 (外部的)state
對象 到(UI 組件的)props
對象 的映射關係。
state
對象/**
* 參數state表明的是 整個網頁的「狀態」。
*/
const mapStateToProps = (state) => {
return {
todos: getVisibleTodos(state.todos, state.visibilityFilter) // 從算出 的值 ---->
}
}statetodos
從state
算出 todos
的值。
const getVisibleTodos = (todos, filter) => {
switch (filter) {
case 'SHOW_ALL':
return todos
case 'SHOW_COMPLETED':
return todos.filter(t => t.completed)
case 'SHOW_ACTIVE':
return todos.filter(t => !t.completed)
default:
throw new Error('Unknown filter: ' + filter)
}
}
props
對象// 容器組件的代碼 // <FilterLink filter="SHOW_ALL"> // All // </FilterLink> const mapStateToProps = (state, ownProps) => { return { active: ownProps.filter === state.visibilityFilter } }
使用ownProps
做爲參數後,若是容器組件的參數發生變化,也會引起 UI 組件從新渲染。
connect
方法能夠省略mapStateToProps
參數,那樣的話,UI 組件就不會訂閱Store,就是說 Store 的更新不會引發 UI 組件的更新。
mapDispatchToProps
創建映射:(外部的)
state
對象 ====> (UI 組件的)props
對象創建映射:UI 組件的參數 ====>
store.dispatch
方法
定義了哪些用戶的操做應該看成 Action,傳給 Store。
const mapDispatchToProps = (
dispatch,
ownProps
) => {
return {
onClick: () => {
dispatch({
type: 'SET_VISIBILITY_FILTER',
filter: ownProps.filter
});
}
};
}
思考題:有了connect -> react-reduct,就不須要:Every listener registered with store.subscribe(listener) will now be invoked.
connect
方法生成容器組件之後,須要讓容器組件拿到state
對象,才能生成 UI 組件的參數。
一種解決方法是將state
對象做爲參數,傳入容器組件。可是,這樣作比較麻煩,尤爲是容器組件可能在很深的層級,一級級將state
傳下去就很麻煩。
React-Redux 提供Provider
組件,可讓容器組件拿到state
。其實就是在講下圖。
利用React
組件的context
屬性,Provider
在根組件外面包了一層,這樣一來,App
的全部子組件就默認均可以拿到state
了。
import { Provider } from 'react-redux' import { createStore } from 'redux' import todoApp from './reducers' import App from './components/App' let store = createStore(todoApp); render(
<Providerstore={store}> // <----------- 這裏就是重點! <App /> </Provider>,
document.getElementById('root') )
子組件就能夠從context
拿到store
/* 容器組件,visibleTodoList */
class VisibleTodoList extends Component {
componentDidMount() {
const { store } = this.context;
this.unsubscribe = store.subscribe(() =>
this.forceUpdate()
);
}
render() {
const props = this.props;
const { store } = this.context;
const state = store.getState();
// ...
}
}
VisibleTodoList.contextTypes = {
store: React.PropTypes.object
}
Ref: jackielii/simplest-redux-example
Ref: bbandydd/serverless-client-s3 【看上去將來會有用】
--------------------------------------------------------------------------------------------
Ref: bbandydd/React_Startkit 【代碼講解】
Ref: [線上讀書會] andy workshop 一天入魂 react-redux【五個小時~】
3
從 3:34:05 / 5:14:37 開始講解代碼。
container:更新狀態;從redux's state去取,與redux溝通。
component:畫面如何呈現 based on props,不用redux。
Jeff: 下圖可見,number & increment放在了」外面「。
---> main.js中的標籤<Panel />
[container/Panel.js]
---> Panel組件的具體實現。
---> 前者寫起來簡單些。
export default Panel;
import Panel from '../';
export const Number;
import {Number} from 'Panel';
== 先提出一個疑點 ==
原始方式:狀態的改變(onClick事件在panel裏)
Redux方式:狀態的改變要放在action中,也就是,onClick實則在this,props傳來的action中。
== 建立動做 ==
視頻講解 - 4:01:40 / 5:14:37
點擊按鍵,觸發action,只是發了一個信號。以下,發了一個INCREMENT signal.
[actions/counterAction.js]
== 執行動做 ==
去reducer中去驗證,即:計算新狀態(硬拷貝)。
狀態 object + 負載 object ==> 新的 狀態 object。
[reducers/counterReducer.js]
== 合併動做 ==
建立 store,將總的reducer做爲參數進行了」綁定「。
[store/configureStore.js]
視頻講解 - 4:30:46 / 5:14:37
若有沒有這個參數,全部的state就所有給了Panel(contrainer角色)處理;
有這兩個參數,就是」只處理「當前用到的。
export default connect(mapStateToProps, mapDispatchToProps)(Panel);
解決什麼問題?
下圖 line 17 爲什麼能方便地直接獲取 」當下所需「 的變量,這即是 connect 的功勞。
== 第一個參數 ==
line 31, 表示全部的state。return的就是其中須要用到的。
== 第二個參數 ==
line 39,至關於替代了 dispatch(counterAction)。
[main.js]
configureStore 就是 createStore() 的地方。
有了Redux框架,新功能的添加就成了體力活,這也是 Redux 框架的優點和迷人的地方。
Btn裏這個button set裏,繼續添加一個button。
注意:這裏取代了dispatch(...)方法,爲何能這樣呢?詳見Step 6。
在Panel.js中 (container) 添加對應的使用方式。