react-redux把組件分爲UI組件和容器組件。先看圖下圖:
下面讓咱們帶着問題學習一下react-redux:
1. react-redux如何將store分發到不一樣組件中?
2. react-redux如何作到store發生變化, 對應的組件從新render, 也就是說如何subscribe store?html
用於包裹UI組件生成容器組件, 也就是connect鏈接的意思。
connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options]); // mapStateToProps(state, ownProps?): function, 返回的是Object(stateProps), 該方法將容器組件state映射到UI組件的props, 也就是輸入邏輯, 重點是mapStateToProps會訂閱store,每當store更新時, 會從新執行, 若是計算出的UI組件的參數發生變化, 就會觸發UI組件的從新渲染。state, 表明監聽的全局store,也能夠說是全局的state, ownProps表示該組件自身攜帶的props方法。 // mapDispatchToProps(dispatch, [ownProps]):function/Object, 若是返回的是對象,則對應每一個Action 的函數名, 在UI組件中調用須要dispatch, 若是返回的是函數,則已經被dispatch包裹(能夠用bindActionCreators)。 該參數主要是映射用戶動做Action, 從UI組件傳遞出去, 也就是輸出邏輯,這裏能夠用到redux的api bindActionCreators, // mergeProps(stateProps, dispatchProps, ownProps) 指定傳入的UI組件的props, 默認是Object.assign({}, ownProps, stateProps, dispatchProps) // options: Obejct, 能夠進一步定義connect功能, 如定義store的來源,指定props的一些更新規則等。 // action,js ... export const initSelectConcact = (streamConcacts: StreamToConcact): InitSelectConcactAction => ({ type: LOCAL_CONCACT, streamConcacts, }); export const testFetch = (dispatch) => dispatch(initSelectConcact([])); // UnreadCards.js class UnreadCards ... componentDidMount() { this.props.fetchStreamConcact(); } const mapStateToProps = (state, ownProps) => ({ users: getUsers(state), }); const mapDispatchToProps = (dispatch, ownProps) => ({ fetchStreamConcact: () => testFetch(dispatch), // 或者以下 fetchStream: bindActionCreators(initSelectConcact, dispatch) }); const mergeProps = (stateProps, dispatchProps, ownProps) => { console.log('mergeProps', stateProps, dispatchProps, ownProps); return Object.assign({}, ownProps, { todos: stateProps.todos[ownProps.userId], addTodo: (text) => dispatchProps.addTodo(ownProps.userId, text), }); }; const options = { pure: true, storeKey: 'store', }; export default connect(mapStateToProps, mapDispatchToProps, mergeProps, options)(UnreadCards);
connect
生成容器組件後,須要將是state數據傳遞到子組件中, 有兩種方案:react
A -> B -> C
組件數據中傳遞, 能夠經過props一層層的傳遞。A -> B -> C
利用React 的 context屬性, 將state綁在跟組件A的context中, A下面的全部子組件均可以經過context拿到是state。爲避免在connect參數mapDispatchToProps
中反覆寫action, 我將全部Action經過方法綁定在props的actions上, 不用每次去映射當前頁面所需的action。redux
import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; // 全部頁面action集合 import * as actions from './actions'; // 緩存actions, 不用每次render都從新加載 let cachedActions; // action經過bindActionCreators綁定dispatch, const bindActions = (dispatch, ownProps) => { if (!cachedActions) { cachedActions = { dispatch, actions: bindActionCreators(actions, dispatch), }; } return cachedActions; }; const connectWithActions = (mapStateToProps: MapStateToProps, mergeProps, options) => ( component, ) => connect(mapStateToProps, bindActions, mergeProps, options)(component); export default connectWithActions; // 用法 class HomeScreen extennds Component { componentWillMount() { this.props.actions.getList(); } ... } export default connectWithActions(state => ({ users: state.users, }))(HomeScreen);
-----完-----api
參考文章緩存