Äú¿ÉÒÔ¾èÖú£¬Ö§³ÖÎÒÃǵĹ«ÒæÊÂÒµ¡£

1Ôª 10Ôª 50Ôª





ÈÏÖ¤Â룺  ÑéÖ¤Âë,¿´²»Çå³þ?Çëµã»÷Ë¢ÐÂÑéÖ¤Âë ±ØÌî



  ÇóÖª ÎÄÕ ÎÄ¿â Lib ÊÓÆµ iPerson ¿Î³Ì ÈÏÖ¤ ×Éѯ ¹¤¾ß ½²×ù Model Center   Code  
»áÔ±   
   
 
     
   
 ¶©ÔÄ
  ¾èÖú
¡¾ÖØÑ§React¡¿¶¯ÊÖʵÏÖÒ»¸öreact-redux
 
×÷ÕߣºÁõСϦ
  1680  次浏览      29
  2019-11-4
 
±à¼­ÍƼö:
ÎÄÕ·ÖÎöÁËreact-reduxµÄ¸ÅÄÂß¼­¸´ÓõÄÏêϸ½éÉÜ£¬ÒÔ¼°Ð¾ÉÁ½¸ö°æ±¾µÄ context API£¬Ï£Íû¿ÉÒÔΪÄúµÄѧϰ´øÀ´°ïÖú¡£
±¾ÎÄÀ´×ÔÓÚ¾ò½ð¼¼ÊõרÀ¸£¬ÓÉ»ðÁú¹ûÈí¼þLuca±à¼­¡¢ÍƼö¡£

react-redux ÊÇʲô

react-redux ÊÇ redux ¹Ù·½ React °ó¶¨¿â¡£Ëü°ïÖúÎÒÃÇÁ¬½ÓUI²ãºÍÊý¾Ý²ã¡£±¾ÎÄÄ¿µÄ²»ÊǽéÉÜ react-redux µÄʹÓ㬶øÊÇÒª¶¯ÊÖʵÏÖÒ»¸ö¼òÒ×µÄ react-redux£¬Ï£ÍûÄܹ»¶ÔÄãÓÐËù°ïÖú¡£

Ê×ÏÈ˼¿¼Ò»Ï£¬ÌÈÈô²»Ê¹Óà react-redux£¬ÎÒÃÇµÄ react ÏîÄ¿ÖиÃÈçºÎ½áºÏ redux ½øÐпª·¢ÄØ¡£

ÿ¸öÐèÒªÓë redux ½áºÏʹÓõÄ×é¼þ£¬ÎÒÃǶ¼ÐèÒª×öÒÔϼ¸¼þÊ£ºÔÚ×é¼þÖлñÈ¡ store ÖеÄ״̬

¼àÌý store ÖÐ״̬µÄ¸Ä±ä£¬ÔÚ״̬¸Ä±äʱ£¬Ë¢ÐÂ×é¼þ

ÔÚ×é¼þÐ¶ÔØÊ±£¬ÒƳý¶Ô״̬±ä»¯µÄ¼àÌý¡£

ÈçÏÂ:

import React from 'react';
import store from '../store';
import actions from '../store/actions/counter';
/**
* reducer ÊÇ combineReducer({counter, ...})
* state µÄ½á¹¹Îª
* {
* counter: {number: 0},
* ....
* }
*/
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = {
number: store.getState().counter.number
}
}
componentDidMount() {
this.unsub = store.subscribe(() => {
if(this.state.number === store.getState().counter.number) {
return;
}
this.setState({
number: store.getState().counter.number
});
});
}
render() {
return (
<div>
<p>{`number: ${this.state.number}`}</p>
<button onClick={() => {store.dispatch(actions.add(2))}}>+</button>
<button onClick={() => {store.dispatch(actions.minus(2))}}>-</button>
<div>
)
}
componentWillUnmount() {
this.unsub();
}
}

½¨Á¢¿í´øÁ¬½ÓÈç¹ûÎÒÃǵÄÏîÄ¿ÖÐÓкܶà×é¼þÐèÒªÓë redux ½áºÏʹÓã¬ÄÇôÕâЩ×é¼þ¶¼ÐèÒªÖØ¸´Ð´ÕâЩÂß¼­¡£ÏÔÈ»£¬ÎÒÃÇÐèÒªÏë°ì·¨¸´ÓÃÕⲿ·ÖµÄÂß¼­£¬²»È»»áÏÔµÃÎÒÃǺܴÀ¡£ÎÒÃÇÖªµÀ£¬react Öи߽××é¼þ¿ÉÒÔʵÏÖÂß¼­µÄ¸´Óá£

ÎÄÖÐËùÓõ½µÄ [Counter ´úÂë] (github.com/YvetteLau/B¡­) ÖÐµÄ myreact-redux/counter ÖУ¬½¨ÒéÏÈ clone ´úÂ룬µ±È»À²£¬Èç¹û¾õµÃ±¾ÎIJ»´íµÄ»°£¬¸ø¸östar¹ÄÀø¡£

Âß¼­¸´ÓÃ

ÔÚ src Ŀ¼ÏÂн¨Ò»¸ö react-redux Îļþ¼Ð£¬ºóÐøµÄÎļþ¶¼Ð½¨ÔÚ´ËÎļþ¼ÐÖС£

´´½¨ connect.js Îļþ

Îļþ´´½¨ÔÚ react-redux/components Îļþ¼ÐÏÂ:

ÎÒÃǽ«Öظ´µÄÂß¼­±àд connect ÖС£

import React, { Component } from 'react';
import store from '../../store';
export default function connect (WrappedComponent) {
return class Connect extends Component {
constructor(props) {
super(props);
this.state = store.getState();
}
componentDidMount() {
this.unsub = store.subscribe(() => {
this.setState({
this.setState(store.getState());
});
});
}
componentWillUnmount() {
this.unsub();
}
render() {
return (
<WrappedComponent {...this.state} {...this.props}/>
)
}
}
}

½¨Á¢¿í´øÁ¬½ÓÓиöССµÄÎÊÌ⣬¾¡¹ÜÕâÂß¼­ÊÇÖØ¸´µÄ£¬µ«ÊÇÿ¸ö×é¼þÐèÒªµÄÊý¾ÝÊDz»Ò»ÑùµÄ£¬²»Ó¦¸Ã°ÑËùÓеÄ״̬¶¼´«µÝ¸ø×é¼þ£¬Òò´ËÎÒÃÇÏ£ÍûÔÚµ÷Óà connect ʱ£¬Äܹ»½«ÐèÒªµÄ״̬ÄÚÈݸæÖª connect¡£ÁíÍ⣬×é¼þÖпÉÄÜ»¹ÐèÒªÐÞ¸Ä״̬£¬ÄÇôҲҪ¸æËß connect£¬ËüÐèÒªÅÉ·¢ÄÄЩ¶¯×÷£¬·ñÔò connect ÎÞ·¨ÖªµÀ¸Ã°ó¶¨ÄÇЩ¶¯×÷¸øÄã¡£

Ϊ´Ë£¬ÎÒÃÇÐÂÔöÁ½¸ö²ÎÊý£ºmapStateToProps ºÍ mapDispatchToProps£¬ÕâÁ½¸ö²ÎÊý¸ºÔð¸æËß connect ×é¼þÐèÒªµÄ state ÄÚÈݺͽ«ÒªÅÉ·¢µÄ¶¯×÷¡£

mapStateToProps ºÍ mapDispatchToProps

ÎÒÃÇÖªµÀ mapStateToProps ºÍ mapDispatchToProps µÄ×÷ÓÃÊÇʲô£¬µ«ÊÇĿǰΪֹ£¬ÎÒÃÇ»¹²»Çå³þ£¬ÕâÁ½¸ö²ÎÊýÓ¦¸ÃÊÇÒ»¸öʲôÑùµÄ¸ñʽ´«µÝ¸ø connect ȥʹÓá£

import { connect } from 'react-redux';
....
//connect µÄʹÓÃ
export default connect(mapStateToProps, mapDispatchToProps)(Counter);

mapStateToProps ¸æËß connect £¬×é¼þÐèÒª°ó¶¨µÄ״̬¡£

mapStateToProps ÐèÒª´ÓÕû¸ö״̬ÖÐÌôÑ¡×é¼þÐèÒªµÄ״̬£¬µ«ÊÇÔÚµ÷Óà connect ʱ£¬ÎÒÃDz¢²»ÄÜ»ñÈ¡µ½ store £¬²»¹ý connect ÄÚ²¿ÊÇ¿ÉÒÔ»ñÈ¡µ½ store µÄ£¬Îª´Ë£¬ÎÒÃǽ« mapStateToProps ¶¨ÒåΪһ¸öº¯Êý£¬ÔÚ connect ÄÚ²¿µ÷ÓÃËü£¬½« store ÖÐµÄ state ´«µÝ¸øËü£¬È»ºó½«º¯Êý·µ»ØµÄ½á¹û×÷ΪÊôÐÔ´«µÝ¸ø×é¼þ¡£×é¼þÖÐͨ¹ý this.props.XXX À´»ñÈ¡¡£Òò´Ë£¬mapStateToProps µÄ¸ñʽӦ¸ÃÀàËÆÏÂÃæÕâÑù:

//½« store.getState() ´«µÝ¸ø mapStateToProps
mapStateToProps = state => ({
number: state.counter.number
});

mapDispatchToProps ¸æËß connect£¬×é¼þÐèÒª°ó¶¨µÄ¶¯×÷¡£

»ØÏëһϣ¬×é¼þÖÐÅÉ·¢¶¯×÷£ºstore.dispatch({actions.add(2)})¡£connect °ü×°Ö®ºó£¬ÎÒÃÇÈÔÒªÄÜÅÉ·¢¶¯×÷£¬¿Ï¶¨ÊÇ this.props.XXX() ÕâÑùµÄÒ»ÖÖ¸ñʽ¡£

±ÈÈ磬¼ÆÊýÆ÷µÄÔö¼Ó£¬µ÷Óà this.props.add(2)£¬¾ÍÊÇÐèÒªÅÉ·¢ store.dispatch({actions.add(2)})£¬Òò´Ë add ÊôÐÔ£¬¶ÔÓ¦µÄÄÚÈݾÍÊÇ (num) => { store.dispatch({actions.add(num)}) }¡£´«µÝ¸ø×é¼þµÄÊôÐÔÀàËÆÏÂÃæÕâÑù:

{
add: (num) => {
store.dispatch(actions.add(num))
},
minus: (num) => {
store.dispatch(actions.minus(num))
}
}

ºÍ mapStateToProps Ò»Ñù£¬ÔÚµ÷Óà connect ʱ£¬ÎÒÃDz¢²»ÄÜ»ñÈ¡µ½ store.dispatch£¬Òò´ËÎÒÃÇÒ²ÐèÒª½« mapDispatchToProps Éè¼ÆÎªÒ»¸öº¯Êý£¬ÔÚ connect ÄÚ²¿µ÷Óã¬ÕâÑù¿ÉÒÔ½« store.dispatch ´«µÝ¸øËü¡£ËùÒÔ£¬mapStateToProps Ó¦¸ÃÊÇÏÂÃæÕâÑùµÄ¸ñʽ:

//½« store.dispacth ´«µÝ¸ø mapDispatchToProps
mapDispatchToProps = (dispatch) => ({
add: (num) => {
dispatch(actions.add(num))
},
minus: (num) => {
dispatch(actions.minus(num))
}
})

ÖÁ´Ë£¬ÎÒÃÇÒѾ­¸ãÇå³þ mapStateToProps ºÍ mapDispatchToProps µÄ¸ñʽ£¬ÊÇʱºò½øÒ»²½¸Ä½ø connect ÁË¡£

connect 1.0 °æ±¾

import React, { Component } from 'react';
import store from '../../store';
export default function connect (mapStateToProps, mapDispatchToProps) {
return function wrapWithConnect (WrappedComponent) {
return class Connect extends Component {
constructor(props) {
super(props);
this.state = mapStateToProps(store.getState());
this.mappedDispatch = mapDispatchToProps(store.dispatch);
}
componentDidMount() {
this.unsub = store.subscribe(() => {
const mappedState = mapStateToProps(store.getState());
//TODO ×öÒ»²ãdz±È½Ï£¬Èç¹û״̬ûÓиı䣬Ôò²»setState
this.setState(mappedState);
});
}
componentWillUnmount() {
this.unsub();
}
render() {
return (
<WrappedComponent {...this.props} {...this.state} {...this.mappedDispatch} />
)
}
}
}
}

ÎÒÃÇÖªµÀ£¬connect ÊÇ×÷Ϊ react-redux ¿âµÄ·½·¨ÌṩµÄ£¬Òò´ËÎÒÃDz»¿ÉÄÜÖ±½ÓÔÚ connect.js ÖÐÈ¥µ¼Èë store£¬Õâ¸ö store Ó¦¸ÃÓÉʹÓà react-redux µÄÓ¦Óô«Èë¡£react ÖÐÊý¾Ý´«µÝÓÐÁ½ÖÖ£ºÍ¨¹ýÊôÐÔ props »òÕßÊÇͨ¹ýÉÏÏÂÎĶÔÏó context£¬Í¨¹ý connect °ü×°µÄ×é¼þÔÚÓ¦ÓÃÖзֲ¼£¬¶ø context Éè¼ÆÄ¿µÄÊÇΪÁ˹²ÏíÄÇЩ¶ÔÓÚÒ»¸ö×é¼þÊ÷¶øÑÔÊÇ¡°È«¾Ö¡±µÄÊý¾Ý¡£

ÎÒÃÇÐèÒª°Ñ store ·ÅÔÚ context ÉÏ£¬ÕâÑù¸ù×é¼þϵÄËùÓÐ×ÓËï×é¼þ¶¼¿ÉÒÔ»ñÈ¡µ½ store¡£Õⲿ·ÖÄÚÈÝ£¬ÎÒÃǵ±È»¿ÉÒÔ×Ô¼ºÔÚÓ¦ÓÃÖбàдÏàÓ¦´úÂ룬²»¹ýºÜÏÔÈ»£¬ÕâЩ´úÂëÔÚÿ¸öÓ¦ÓÃÖж¼ÊÇÖØ¸´µÄ¡£Òò´ËÎÒÃǰÑÕⲿ·ÖÄÚÈÝÒ²·â×°ÔÚ react-redux ÄÚ²¿¡£

´Ë´¦£¬ÎÒÃÇʹÓÃ¾ÉµÄ Context API À´Ð´(¼øÓÚÎÒÃÇʵÏÖµÄ react-redux 4.x ·ÖÖ§µÄ´úÂ룬Òò´ËÎÒÃÇʹÓþɰæµÄ context API)¡£

Provider

ÎÒÃÇÐèÒªÌṩһ¸ö Provider ×é¼þ£¬ËüµÄ¹¦ÄܾÍÊǽÓÊÕÓ¦Óô«µÝ¹ýÀ´µÄ store£¬½«Æä¹ÒÔÚ context ÉÏ£¬ÕâÑùËüµÄ×ÓËï×é¼þ¾Í¶¼¿ÉÒÔͨ¹ýÉÏÏÂÎĶÔÏó»ñÈ¡µ½ store¡£

н¨ Provider.js Îļþ

Îļþ´´½¨ÔÚ react-redux/components Îļþ¼ÐÏ£º

import React, { Component } from 'react';
import PropTypes from 'prop-types';
export default class Provider extends Component {
static childContextTypes = {
store: PropTypes.shape({
subscribe: PropTypes.func.isRequired,
dispatch: PropTypes.func.isRequired,
getState: PropTypes.func.isRequired
}).isRequired
}

constructor(props) {
super(props);
this.store = props.store;
}
getChildContext() {
return {
store: this.store
}
}
render() {
/**
* Ôçǰ·µ»ØµÄÊÇ return Children.only(this.props.children)
* µ¼ÖÂProviderÖ»Äܰü¹üÒ»¸ö×Ó×é¼þ£¬ºóÀ´È¡ÏûÁË´ËÏÞÖÆ
* Òò´Ë´Ë´¦£¬ÎÒÃÇÖ±½Ó·µ»Ø this.props.children
*/
return this.props.children
}
}

н¨Ò»¸ö index.js Îļþ

Îļþ´´½¨ÔÚ react-redux Ŀ¼ÏÂ:

´ËÎļþÖ»×öÒ»¼þÊ£¬¼´½« connect ºÍ Provider µ¼³ö

import connect from './components/connect';
import Provider from './components/Provider';

export {
connect,
Provider
}

Provider µÄʹÓÃ

ʹÓÃʱ£¬ÎÒÃÇÖ»ÐèÒªÒýÈë Provider£¬½« store ´«µÝ¸ø Provider¡£

mport React, { Component } from 'react';
import { Provider } from '../react-redux';
import store from './store';
import Counter from './Counter';
export default class App extends Component {
render() {
return (
<Provider store={store}>
<Counter />
</Provider>
)
}
}

ÖÁ´Ë£¬Provider µÄÔ´ÂëºÍʹÓÃÒѾ­ËµÃ÷Çå³þÁË£¬²»¹ýÏàÓ¦µÄ connect Ò²ÐèÒª×öһЩÐ޸ģ¬ÎªÁËͨÓÃÐÔ£¬ÎÒÃÇÐèÒª´Ó context ÉÏÈ¥»ñÈ¡ store£¬È¡´ú֮ǰµÄµ¼Èë¡£

connect 2.0 °æ±¾

import React, { Component } from 'react';
import PropTypes from 'prop-types';
export default function connect(mapStateToProps, mapDispatchToProps) {
return function wrapWithConnect(WrappedComponent) {
return class Connect extends Component {
//PropTypes.shape Õⲿ·Ö´úÂëÓë Provider ÖÐÖØ¸´£¬Òò´ËºóÃæÎÒÃÇ¿ÉÒÔÌáÈ¡³öÀ´
static contextTypes = {
store: PropTypes.shape({
subscribe: PropTypes.func.isRequired,
dispatch: PropTypes.func.isRequired,
getState: PropTypes.func.isRequired
}).isRequired
}
constructor(props, context) {
super(props, context);
this.store = context.store;
//Ô´ÂëÖÐÊǽ« store.getState() ¸øÁË this.state
this.state = mapStateToProps(this.store.getState());
this.mappedDispatch = mapDispatchToProps(this.store.dispatch);
}
componentDidMount() {
this.unsub = this.store.subscribe(() => {
const mappedState = mapStateToProps(this.store.getState());
//TODO ×öÒ»²ãdz±È½Ï£¬Èç¹û״̬ûÓиı䣬ÔòÎÞÐè setState
this.setState(mappedState);
});
}
componentWillUnmount() {
this.unsub();
}
render() {
return (
<WrappedComponent {...this.props} {...this.state} {...this.mappedDispatch} />
)
}
}
}
}

ʹÓà connect ¹ØÁª Counter Óë store ÖеÄÊý¾Ý¡£

import React, { Component } from 'react';
import { connect } from '../react-redux';
import actions from '../store/actions/counter';
class Counter extends Component {
render() {
return (
<div>
<p>{`number: ${this.props.number}`}</p>
<button onClick={() => { this.props.add(2) }}>+</button>
<button onClick={() => { this.props.minus(2) }}>-</button>
</div>
)
}
}
const mapStateToProps = state => ({
number: state.counter.number
});
const mapDispatchToProps = (dispatch) => ({
add: (num) => {
dispatch(actions.add(num))
},
minus: (num) => {
dispatch(actions.minus(num))
}
});export default connect(mapStateToProps, mapDispatchToProps)(Counter);

store/actions/counter.js ¶¨ÒåÈçÏ£º

import { INCREMENT, DECREMENT } from '../action-types';
const counter = {
add(number) {
return {
type: INCREMENT,
number
}
},
minus(number) {
return {
type: DECREMENT,
number
}
}
}
export default counter;

ÖÁ´Ë£¬ÎÒÃÇµÄ react-redux ¿âÒѾ­¿ÉÒÔʹÓÃÁË£¬²»¹ýºÜÓкܶàϸ½ÚÎÊÌâ´ý´¦Àí:mapDispatchToProps µÄ¶¨ÒåдÆðÀ´ÓеãÂé·³£¬²»¹»¼ò½à

´ó¼ÒÊÇ·ñ»¹¼ÇµÃ redux ÖÐµÄ bindActionCreators£¬½èÖúÓÚ´Ë·½·¨£¬ÎÒÃÇ¿ÉÒÔÔÊÐí´«µÝ actionCreator ¸ø connect£¬È»ºóÔÚ connect ÄÚ²¿½øÐÐת»»¡£connect ºÍ Provider ÖÐµÄ store µÄ PropType ¹æÔò¿ÉÒÔÌáÈ¡³öÀ´£¬±ÜÃâ´úÂëµÄÈßÓàmapStateToProps ºÍ mapDispatchToProps ¿ÉÒÔÌṩĬÈÏÖµ

mapStateToProps ĬÈÏֵΪ state => ({}); ²»¹ØÁª state£»

mapDispatchToProps µÄĬÈÏֵΪ dispatch => ({dispatch})£¬½« store.dispatch ·½·¨×÷ΪÊôÐÔ´«µÝ¸ø±»°ü×°µÄÊôÐÔ¡£Ä¿Ç°£¬ÎÒÃǽö´«µÝÁË store.getState() ¸ø mapStateToProps£¬µ«ÊǺܿÉÄÜÔÚɸѡ¹ýÂËÐèÒªµÄ state ʱ£¬ÐèÒªÒÀ¾Ý×é¼þ×ÔÉíµÄÊôÐÔ½øÐд¦Àí£¬Òò´Ë£¬¿ÉÒÔ½«×é¼þ×ÔÉíµÄÊôÐÔÒ²´«µÝ¸ø mapStateToProps£¬Í¬ÑùµÄÔ­Òò£¬Ò²½«×ÔÉíÊôÐÔ´«µÝ¸ø mapDispatchToProps¡£

connect 3.0 °æ±¾

ÎÒÃǽ« store µÄ PropType ¹æÔòÌáÈ¡³öÀ´£¬·ÅÔÚ utils/storeShape.js ÎļþÖС£

dz±È½ÏµÄ´úÂë·ÅÔÚ utils/shallowEqual.js ÎļþÖУ¬Í¨ÓõÄdz±È½Ïº¯Êý£¬´Ë´¦²»Áгö£¬ÓÐÐËȤ¿ÉÒÔÖ±½ÓÔĶÁÏ´úÂë¡£

import React, { Component } from 'react';
import { bindActionCreators } from 'redux';
import storeShape from '../utils/storeShape';
import shallowEqual from '../utils/shallowEqual';
/**
* mapStateToProps ĬÈϲ»¹ØÁªstate
* mapDispatchToProps ĬÈÏֵΪ dispatch => ({dispatch})£¬½« `store.dispatch` ·½·¨×÷ΪÊôÐÔ´«µÝ¸ø×é¼þ
*/
const defaultMapStateToProps = state => ({});
const defaultMapDispatchToProps = dispatch => ({ dispatch });
export default function connect(mapStateToProps, mapDispatchToProps) {
if(!mapStateToProps) {
mapStateToProps = defaultMapStateToProps;
}
if (!mapDispatchToProps) {
//µ± mapDispatchToProps Ϊ null/undefined/false...ʱ£¬Ê¹ÓÃĬÈÏÖµ
mapDispatchToProps = defaultMapDispatchToProps;
}
return function wrapWithConnect(WrappedComponent) {
return class Connect extends Component {
static contextTypes = {
store: storeShape
};
constructor(props, context) {
super(props, context);
this.store = context.store;
//Ô´ÂëÖÐÊǽ« store.getState() ¸øÁË this.state
this.state = mapStateToProps(this.store.getState(), this.props);
if (typeof mapDispatchToProps === 'function') {
this.mappedDispatch = mapDispatchToProps(this.store.dispatch, this.props);
} else {
//´«µÝÁËÒ»¸ö actionCreator ¶ÔÏó¹ýÀ´
this.mappedDispatch = bindActionCreators(mapDispatchToProps, this.store.dispatch);
}
}
componentDidMount() {
this.unsub = this.store.subscribe(() => {
const mappedState = mapStateToProps(this.store.getState(), this.props);
if (shallowEqual(this.state, mappedState)) {
return;
}
this.setState(mappedState);
});
}
componentWillUnmount() {
this.unsub();
}
render() {
return (
<WrappedComponent {...this.props} {...this.state} {...this.mappedDispatch} />
)
}
}
}
}

ÏÖÔÚ£¬ÎÒÃÇµÄ connect ÔÊÐí mapDispatchToProps ÊÇÒ»¸öº¯Êý»òÕßÊÇ actionCreators ¶ÔÏó£¬ÔÚ mapStateToProps ºÍ mapDispatchToProps ȱʡ»òÕßÊÇ null ʱ£¬Ò²ÄܱíÏÖÁ¼ºÃ¡£

²»¹ý»¹ÓÐÒ»¸öÎÊÌ⣬connect ·µ»ØµÄËùÓÐ×é¼þÃû¶¼ÊÇ Connect£¬²»±ãÓÚµ÷ÊÔ¡£Òò´ËÎÒÃÇ¿ÉÒÔΪÆäÐÂÔö displayName¡£

connect 4.0 °æ±¾

import React, { Component } from 'react';
import { bindActionCreators } from 'redux';
import storeShape from '../utils/storeShape';
import shallowEqual from '../utils/shallowEqual';
/**
* mapStateToProps ȱʡʱ£¬²»¹ØÁªstate
* mapDispatchToProps ȱʡʱ£¬ÉèÖÃÆäĬÈÏֵΪ dispatch => ({dispatch})£¬½«`store.dispatch` ·½·¨×÷ΪÊôÐÔ´«µÝ¸ø×é¼þ
*/
const defaultMapStateToProps = state => ({});
const defaultMapDispatchToProps = dispatch => ({ dispatch });
function getDisplayName(WrappedComponent) {
return WrappedComponent.displayName || WrappedComponent.name || 'Component';
}
export default function connect(mapStateToProps, mapDispatchToProps) {
if(!mapStateToProps) {
mapStateToProps = defaultMapStateToProps;
}
if(!mapDispatchToProps) {
//µ± mapDispatchToProps Ϊ null/undefined/false...ʱ£¬Ê¹ÓÃĬÈÏÖµ
mapDispatchToProps = defaultMapDispatchToProps;
}
return function wrapWithConnect (WrappedComponent) {
return class Connect extends Component {
static contextTypes = storeShape;
static displayName = `Connect(${getDisplayName(WrappedComponent)})`;
constructor(props) {
super(props);
//Ô´ÂëÖÐÊǽ« store.getState() ¸øÁË this.state
this.state = mapStateToProps(store.getState(), this.props);
if(typeof mapDispatchToProps === 'function') {
this.mappedDispatch = mapDispatchToProps(store.dispatch, this.props);
}else{
//´«µÝÁËÒ»¸ö actionCreator ¶ÔÏó¹ýÀ´
this.mappedDispatch = bindActionCreators(mapDispatchToProps, store.dispatch);
}
}
componentDidMount() {
this.unsub = store.subscribe(() => {
const mappedState = mapStateToProps(store.getState(), this.props);
if(shallowEqual(this.state, mappedState)) {
return;
}
this.setState(mappedState);
});
}
componentWillUnmount() {
this.unsub();
}
render() {
return (
<WrappedComponent {...this.props} {...this.state} {...this.mappedDispatch} />
)
}
}
}
}

ÖÁ´Ë£¬react-redux ÎÒÃǾͻù±¾ÊµÏÖÁË£¬²»¹ýÕâ¸ö´úÂë²¢²»ÍêÉÆ£¬±ÈÈ磬ref ¶ªÊ§µÄÎÊÌ⣬×é¼þµÄ props ±ä»¯Ê±£¬ÖØÐ¼ÆËã this.state ºÍ this.mappedDispatch£¬Ã»ÓнøÒ»²½½øÐÐÐÔÄÜÓÅ»¯µÈ¡£Äã¿ÉÒÔÔÚ´Ë»ù´¡ÉϽøÒ»²½½øÐд¦Àí¡£

react-redux Ö÷¸É·ÖÖ§µÄ´úÂëÒѾ­Ê¹Óà hooks ¸Äд£¬ºóÆÚÈç¹ûÓÐʱ¼ä£¬»áÊä³öһƪа汾µÄ´úÂë½âÎö¡£

×îºó£¬Ê¹ÓÃÎÒÃÇ×Ô¼º±àдµÄ react-redux ºÍ redux ±àдÁË Todo µÄdemo£¬¹¦ÄÜÕý³££¬´úÂëÔÚ ÔÚ https://github.com/YvetteLau/Blog ÖÐµÄ myreact-redux/todo Ï¡£

¸½ÉÏÐÂÀÏ context API µÄʹÓ÷½·¨£º

context

ĿǰÓÐÁ½¸ö°æ±¾µÄ context API£¬¾ÉµÄ API ½«»áÔÚËùÓÐ 16.x °æ±¾Öеõ½Ö§³Ö£¬µ«ÊÇδÀ´°æ±¾ÖÐ»á±»ÒÆ³ý¡£

context API(ÐÂ)

const MyContext = React.createContext(defaultValue);

´´½¨Ò»¸ö Context ¶ÔÏó¡£µ± React äÖȾһ¸ö¶©ÔÄÁËÕâ¸ö Context ¶ÔÏóµÄ×é¼þ£¬Õâ¸ö×é¼þ»á´Ó×é¼þÊ÷ÖÐÀë×ÔÉí×î½üµÄÄǸöÆ¥ÅäµÄ Provider ÖжÁÈ¡µ½µ±Ç°µÄ context Öµ¡£

×¢Ò⣺ֻÓе±×é¼þËù´¦µÄÊ÷ÖÐûÓÐÆ¥Åäµ½ Provider ʱ£¬Æä defaultValue ²ÎÊý²Å»áÉúЧ¡£

ʹÓÃ

Context.js

Ê×ÏÈ´´½¨ Context ¶ÔÏó

import React from 'react';

const MyContext = React.createContext(null);

export default MyContext;

¸ù×é¼þ( Pannel.js )

½«ÐèÒª¹²ÏíµÄÄÚÈÝ£¬ÉèÖÃÔÚ <MyContext.Provider> µÄ value ÖÐ(¼´ context Öµ)

×Ó×é¼þ±» <MyContext.Provider> °ü¹ü

import React from 'react';
import MyContext from './Context';
import Content from './Content';
class Pannel extends React.Component {
state = {
theme: {
color: 'rgb(0, 51, 254)'
}
}
render() {
return (
// ÊôÐÔÃû±ØÐë½Ð value
<MyContext.Provider value={this.state.theme}>
<Content />
</MyContext.Provider>
)
}
}

×ÓËï×é¼þ( Content.js )

Àà×é¼þ

¶¨Òå Class.contextType: static contextType = ThemeContext;

ͨ¹ý this.context »ñÈ¡ <ThemeContext.Provider> ÖÐ value µÄÄÚÈÝ(¼´ context Öµ)

 

//Àà×é¼þ
import React from 'react';
import ThemeContext from './Context';
class Content extends React.Component {
//¶¨ÒåÁË contextType Ö®ºó£¬¾Í¿ÉÒÔͨ¹ý this.context »ñÈ¡ ThemeContext.Provider value ÖеÄÄÚÈÝ
static contextType = ThemeContext;
render() {
return (
<div style={{color: `2px solid ${this.context.color}`}}>
//....
</div>
)
}
}

º¯Êý×é¼þ

×ÓÔªËØ°ü¹üÔÚ <ThemeContext.Consumer> ÖÐ

<ThemeContext.Consumer> µÄ×ÓÔªËØÊÇÒ»¸öº¯Êý£¬Èë²Î context Öµ£¨Provider ÌṩµÄ value£©¡£´Ë´¦ÊÇ {color: XXX}

import React from 'react';
import ThemeContext from './Context';
export default function Content() {
return (
<ThemeContext.Consumer>
{
context => (
<div style={{color: `2px solid ${context.color}`}}>
//....
</div>
)
}
</ThemeContext.Consumer>
)
}

context API(¾É)

ʹÓÃ

¶¨Òå¸ù×é¼þµÄ childContextTypes (ÑéÖ¤ getChildContext ·µ»ØµÄÀàÐÍ)

¶¨Òå getChildContext ·½·¨

¸ù×é¼þ( Pannel.js )

import React from 'react';
import PropTypes from 'prop-types';
import Content from './Content';
class Pannel extends React.Component {
static childContextTypes = {
theme: PropTypes.object
}
getChildContext() {
return { theme: this.state.theme }
}
state = {
theme: {
color: 'rgb(0, 51, 254)'
}
}
render() {
return (
// ÊôÐÔÃû±ØÐë½Ð value
<>
<Content />
</>
)
}
}

×ÓËï×é¼þ( Content.js )

¶¨Òå×ÓËï×é¼þµÄ contextTypes (ÉùÃ÷ºÍÑéÖ¤ÐèÒª»ñÈ¡µÄ״̬µÄÀàÐÍ)

ͨ¹ý this.context ¼´¿ÉÒÔ»ñÈ¡´«µÝ¹ýÀ´µÄÉÏÏÂÎÄÄÚÈÝ¡£

import React from 'react';
import PropTypes from 'prop-types';
class Content extends React.Component {
static contextTypes = PropTypes.object;
render() {
return (
<div style={{color: `2px solid ${this.context.color}`}}>
//....
</div>
)
}
}

²Î¿¼´úÂë

 
   
1680 ´Îä¯ÀÀ       29
Ïà¹ØÎÄÕÂ

Éî¶È½âÎö£ºÇåÀíÀôúÂë
ÈçºÎ±àд³öÓµ±§±ä»¯µÄ´úÂë
ÖØ¹¹-ʹ´úÂë¸ü¼ò½àÓÅÃÀ
ÍŶÓÏîÄ¿¿ª·¢"±àÂë¹æ·¶"ϵÁÐÎÄÕÂ
Ïà¹ØÎĵµ

ÖØ¹¹-¸ÄÉÆ¼ÈÓдúÂëµÄÉè¼Æ
Èí¼þÖØ¹¹v2
´úÂëÕû½àÖ®µÀ
¸ßÖÊÁ¿±à³Ì¹æ·¶
Ïà¹Ø¿Î³Ì

»ùÓÚHTML5¿Í»§¶Ë¡¢Web¶ËµÄÓ¦Óÿª·¢
HTML 5+CSS ¿ª·¢
ǶÈëʽC¸ßÖÊÁ¿±à³Ì
C++¸ß¼¶±à³Ì