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

1Ôª 10Ôª 50Ôª





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



  ÇóÖª ÎÄÕ ÎÄ¿â Lib ÊÓÆµ iPerson ¿Î³Ì ÈÏÖ¤ ×Éѯ ¹¤¾ß ½²×ù Model Center   Code  
»áÔ±   
   
 
     
   
 ¶©ÔÄ
  ¾èÖú
ReactÓ¦Óüܹ¹ÓëÓ¦ÓÃÉè¼Æ
 
  5734  次浏览      27
 2018-2-28 
 
±à¼­ÍƼö:

±¾ÎÄÀ´×ÔÓÚ21CTO£¬±¾ÎĽÏÏêϸµÄ×ܽáÁ˸öÈË´Ó0µ½1´î½¨Ò»¸öÏîÄ¿¼Ü¹¹µÄ¹ý³Ì£¬¶ÔReact£¬ ReduxÓ¦ÓúÍÏîÄ¿¹¤³Ìʵ¼ù¶¼ÓÐÁ˸üÉîµÄÀí½â¼°Ë¼¿¼£¬ÔÚ´óǰ¶Ë³É³¤Ö®Â·¼ÌÐøíÆíÂǰÐС£

ǰÑÔ

ÏÖÔÚÒѾ­Óкܶà½ÅÊּܹ¤¾ß£¬Èçcreate-react-app£¨https://github.com/facebookincubator/create-react-app£©£¬Ö§³ÖÒ»¼ü´´½¨Ò»¸öReactÓ¦ÓÃÏîÄ¿½á¹¹£¬ºÜ·½±ã£¬µ«ÊÇÏíÊÜ·½±ãµÄͬʱ£¬Ò²Ê§È¥Á˶ÔÏîÄ¿¼Ü¹¹¼°¼¼ÊõÕ»ÍêÕûѧϰµÄ»ú»á£¬¶øÇÒͨ³£½ÅÊּܴ´½¨µÄÓ¦Óü¼Êõ¼Ü¹¹²¢²»ÄÜÍêÈ«Âú×ãÎÒÃǵÄÒµÎñÐèÇó£¬ÐèÒªÎÒÃÇ×Ô¼ºÐ޸ģ¬ÍêÉÆ£¬ËùÒÔÈç¹ûÏ£Íû¶ÔÏîÄ¿¼Ü¹¹ÓиüÉîÕÆ¿Ø£¬×îºÃ»¹ÊÇ´Ó0µ½1Àí½âÒ»¸öÏîÄ¿¡£

ÏîÄ¿½á¹¹Óë¼¼ÊõÕ»

ÎÒÃÇÕâ´ÎµÄʵ¼ù²»×¼±¸Ê¹ÓÃÈκνÅÊּܣ¬ËùÒÔÎÒÃÇÐèÒª×Ô¼º´´½¨Ã¿Ò»¸öÎļþ£¬ÒýÈëÿһ¸ö¼¼ÊõºÍÈý·½¿â£¬×îÖÕÐγÉÍêÕûµÄÓ¦Ó㬰üÀ¨ÎÒÃÇÑ¡ÔñµÄÍêÕû¼¼ÊõÕ»¡£

µÚÒ»²½£¬µ±È»ÊÇ´´½¨Ä¿Â¼£¬ÎÒÃÇÔÚÉÏһƪÒѾ­ÅªºÃ£¬Èç¹ûÄ㻹ûÓдúÂ룬¿ÉÒÔ´ÓGithub»ñÈ¡£º

git clone https://github.com/codingplayboy/react-blog.git
cd react-blog

Éú³ÉÏîÄ¿½á¹¹ÈçÏÂͼ£º

1. srcΪӦÓÃÔ´´úÂëĿ¼£»

2. webpackΪwebpackÅäÖÃĿ¼£»

3. webpack.config.jsΪwebpackÅäÖÃÈë¿ÚÎļþ£»

4. package.jsonΪÏîÄ¿ÒÀÀµ¹ÜÀíÎļþ£»

5. yarn.lockΪÏîÄ¿ÒÀÀµ°æ±¾ËøÎļþ£»

6. .babelrcÎļþ£¬babelµÄÅäÖÃÎļþ£¬Ê¹ÓÃbabel±àÒëReactºÍJavaScript´úÂ룻

7. eslintrcºÍeslintignore·Ö±ðΪeslintÓï·¨¼ì²âÅäÖü°ÐèÒªºöÂÔ¼ì²éµÄÄÚÈÝ»òÎļþ£»

8. postcss.config.jsΪCSSºó±àÒëÆ÷postcssµÄÅäÖÃÎļþ£»

9. API.mdΪAPIÎĵµÈë¿Ú£»

10. docsΪÎĵµÄ¿Â¼£»

11. README.mdΪÏîĿ˵Ã÷Îĵµ£»

½ÓÏÂÀ´µÄ¹¤×÷Ö÷Òª¾ÍÊǷḻsrcĿ¼£¬°üÀ¨´î½¨ÏîÄ¿¼Ü¹¹£¬¿ª·¢Ó¦Óù¦ÄÜ£¬»¹ÓÐ×Ô¶¯»¯£¬µ¥Ôª²âÊԵȣ¬±¾ÆªÖ÷Òª¹Ø×¢ÏîÄ¿¼Ü¹¹µÄ´î½¨£¬È»ºóʹÓü¼Êõջʵ¼ù¿ª·¢¼¸¸öÄ£¿é¡£

¼¼ÊõÕ»

ÏîÄ¿¼Ü¹¹´î½¨ºÜ´ó²¿·ÖÒÀÀµÓÚÏîÄ¿µÄ¼¼ÊõÕ»£¬ËùÒÔÏȶÔÕû¸ö¼¼ÊõÕ»½øÐзÖÎö£¬×ܽ᣺

1. reactºÍreact-dom¿âÊÇÏîĿǰÌ᣻

2. react·ÓÉ£»

3. Ó¦ÓÃ״̬¹ÜÀíÈÝÆ÷£»

4. ÊÇ·ñÐèÒªImmutableÊý¾Ý£»

5. Ó¦ÓÃ״̬µÄ³Ö¾Ã»¯£»

6. Òì²½ÈÎÎñ¹ÜÀí£»

7. ²âÊÔ¼°¸¨Öú¹¤¾ß»òº¯Êý£»

8. ¿ª·¢µ÷ÊÔ¹¤¾ß£»

¸ù¾ÝÒÔÉÏ»®·Ö¾ö¶¨Ñ¡ÓÃÒÔϵÚÈý·½¿âºÍ¹¤¾ß¹¹³ÉÏîÄ¿µÄÍêÕû¼¼ÊõÕ»£º

1. react£¬react-dom£»

2. react-router¹ÜÀíÓ¦Ó÷ÓÉ£»

3. redux×÷ΪJavaScript״̬ÈÝÆ÷£¬react-redux½«ReactÓ¦ÓÃÓëreduxÁ¬½Ó£»

4. Immutable.jsÖ§³ÖImmutable»¯×´Ì¬£¬redux-immutableʹÕû¸öredux store״̬Ê÷Immutable»¯£»

5. ʹÓÃredux-persistÖ§³Öredux״̬Ê÷µÄ³Ö¾Ã»¯£¬²¢Ìí¼Óredux-persist-immutableÍØÕ¹ÒÔÖ§³ÖImmutable»¯×´Ì¬Ê÷µÄ³Ö¾Ã»¯£»

6. ʹÓÃredux-saga¹ÜÀíÓ¦ÓÃÄÚµÄÒì²½ÈÎÎñ£¬ÈçÍøÂçÇëÇó£¬Òì²½¶ÁÈ¡±¾µØÊý¾ÝµÈ£»

7. ʹÓÃjest¼¯³ÉÓ¦ÓòâÊÔ£¬Ê¹ÓÃlodash£¬ramdaµÈ¿ÉÑ¡¸¨ÖúÀ࣬¹¤¾ßÀà¿â£»

8. ¿ÉѡʹÓÃreactotronµ÷ÊÔ¹¤¾ß

Õë¶ÔÒÔÉÏ·ÖÎö£¬ÍêÉÆºóµÄÏîÄ¿½á¹¹Èçͼ£º

¿ª·¢µ÷ÊÔ¹¤¾ß

ReactÓ¦Óÿª·¢Ä¿Ç°ÒѾ­ÓÐÖî¶àµ÷ÊÔ¹¤¾ß£¬³£ÓõÄÈçredux-devtools£¬Reactron£¨https://github.com/infinitered/reactotron£©µÈ¡£

redux-devtools

redux-devtoolsÊÇÖ§³ÖÈÈÖØÔØ£¬»Ø·Åaction£¬×Ô¶¨ÒåUIµÄÒ»¿îRedux¿ª·¢¹¤¾ß¡£

Ê×ÏÈÐèÒª°´ÕÕ¶ÔÓ¦µÄä¯ÀÀÆ÷²å¼þ£¬È»ºóÔÙReduxÓ¦ÓÃÖÐÌí¼ÓÏà¹ØÅäÖ㬾ÍÄÜÔÚä¯ÀÀÆ÷¿ØÖÆÌ¨Öв鿴µ½redux¹¤¾ßÀ¸ÁË£¬ÏêϸÎĵµµã´Ë²é¿´£¨https://github.com/zalmoxisus/redux-devtools-extension#installation£©¡£

È»ºó°²×°ÏîÄ¿ÒÀÀµ¿â£º


yarn add --dev redux-devtools

È»ºóÔÚ´´½¨redux storeʱ½«Æä×÷ΪreduxÇ¿»¯Æ÷´«ÈëcreateStore·½·¨£º


import { applyMiddleware, compose, createStore, combineReducers } from 'redux'
// ĬÈÏΪreduxÌṩµÄ×éºÏº¯Êý
let composeEnhancers = compose

if (__DEV__) {
// ¿ª·¢»·¾³£¬¿ªÆôredux-devtools
const composeWithDevToolsExtension = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
if (typeof composeWithDevToolsExtension === 'function') {
// Ö§³Öredux¿ª·¢¹¤¾ßÍØÕ¹µÄ×éºÏº¯Êý
composeEnhancers = composeWithDevToolsExtension
}
}

// create store
const store = createStore(
combineReducers(...),
initialState,
// ×éºÏreduxÖмä¼ÛºÍ¼ÓÇ¿Æ÷£¬Ç¿»¯redux
composeEnhancers(
applyMiddleware(...middleware),
...enhancers
)
)

1. ÔÚ¿ª·¢»·¾³Ï»ñÈ¡redux-devtoolsÌṩµÄÍØÕ¹×éºÏº¯Êý£»

2. ´´½¨storeʱʹÓÃÍØÕ¹×éºÏº¯Êý×éºÏreduxÖмä¼þºÍÔöÇ¿Æ÷£¬redux-dev-tools±ã»ñµÃÁËÓ¦ÓÃreduxµÄÏà¹ØÐÅÏ¢£»

Reactotron

Reactotron£¨https://github.com/infinitered/reactotron£©ÊÇÒ»¿î¿çƽ̨µ÷ÊÔReact¼°React NativeÓ¦ÓõÄ×ÀÃæÓ¦Óã¬Äܶ¯Ì¬ÊµÊ±¼à²â²¢Êä³öReactÓ¦ÓõÈredux£¬action£¬sagaÒì²½ÇëÇóµÈÐÅÏ¢£¬Èçͼ£º

Ê×ÏȰ²×°£º

yarn add --dev reactotron-react-js

È»ºó³õʼ»¯ReactotronÏà¹ØÅäÖãº

import Reactotron from 'reactotron-react-js';
import { reactotronRedux as reduxPlugin } from 'reactotron-redux';
import sagaPlugin from 'reactotron-redux-saga';

if (Config.useReactotron) {
// refer to https://github.com/infinitered/reactotron for more options!
Reactotron
.configure({ name: 'React Blog' })
.use(reduxPlugin({ onRestore: Immutable }))
.use(sagaPlugin())
.connect();

// Let's clear Reactotron on every time we load the app
Reactotron.clear();

// Totally hacky, but this allows you to not both importing reactotron-react-js
// on every file. This is just DEV mode, so no big deal.
console.tron = Reactotron;
}

È»ºóÆôʹÓÃconsole.tron.overlay·½·¨ÍØÕ¹Èë¿Ú×é¼þ£º

import './config/ReactotronConfig';
import DebugConfig from './config/DebugConfig';

class App extends Component {
render () {
return (
<Provider store={store}>
<AppContainer />
</Provider>
)
}
}

// allow reactotron overlay for fast design in dev mode
export default DebugConfig.useReactotron
? console.tron.overlay(App)
: App

ÖÁ´Ë¾Í¿ÉÒÔʹÓÃReactotron¿Í»§¶Ë²¶»ñÓ¦ÓÃÖз¢ÆðµÄËùÓеÄreduxºÍactionÁË¡£

×é¼þ»®·Ö

React×é¼þ»¯¿ª·¢Ô­ÔòÊÇ×é¼þ¸ºÔðäÖȾUI£¬×é¼þ²»Í¬×´Ì¬¶ÔÓ¦²»Í¬UI£¬Í¨³£×ñÑ­ÒÔÏÂ×é¼þÉè¼ÆË¼Â·£º

1. ²¼¾Ö×é¼þ£º½ö½öÉæ¼°Ó¦ÓÃUI½çÃæ½á¹¹µÄ×é¼þ£¬²»Éæ¼°ÈκÎÒµÎñÂß¼­£¬Êý¾ÝÇëÇó¼°²Ù×÷£»

2. ÈÝÆ÷×é¼þ£º¸ºÔð»ñÈ¡Êý¾Ý£¬´¦ÀíÒµÎñÂß¼­£¬Í¨³£ÔÚrender()º¯ÊýÄÚ·µ»ØÕ¹Ê¾ÐÍ×é¼þ£»

3. չʾÐÍ×é¼þ£º¸ºÔðÓ¦ÓõĽçÃæUIչʾ£»

4. UI×é¼þ£ºÖ¸³éÏó³öµÄ¿ÉÖØÓõÄUI¶ÀÁ¢×é¼þ£¬Í¨³£ÊÇÎÞ״̬×é¼þ£»

Redux

ÏÖÔÚµÄÈκδóÐÍwebÓ¦ÓÃÈç¹ûÉÙÁË״̬¹ÜÀíÈÝÆ÷£¬ÄÇÕâ¸öÓ¦ÓþÍȱÉÙÁËʱ´úÌØÕ÷£¬¿ÉÑ¡µÄ¿âÖîÈçmobx£¬reduxµÈ£¬Êµ¼ÊÉÏ´óͬСÒ죬¸÷È¡ËùÐ裬ÒÔreduxΪÀý£¬reduxÊÇ×î³£ÓõÄReactÓ¦ÓÃ״̬ÈÝÆ÷¿â£¬¶ÔÓÚReact NativeÓ¦ÓÃÒ²ÊÊÓá£

ReduxÊÇÒ»¸öJavaScriptÓ¦ÓõĿÉÔ¤²â״̬¹ÜÀíÈÝÆ÷£¬Ëü²»ÒÀÀµÓÚ¾ßÌå¿ò¼Ü»òÀà¿â£¬ËùÒÔËüÔÚ¶àÆ½Ì¨µÄÓ¦Óÿª·¢ÖÐÓÐ×ÅÒ»ÖµĿª·¢·½Ê½ºÍЧÂÊ£¬ÁíÍâËü»¹ÄܰïÎÒÃÇÇáËɵÄʵÏÖʱ¼äÂÃÐУ¬¼´actionµÄ»Ø·Å¡£

1. Êý¾Ýµ¥Ò»À´Ô´Ô­Ôò£ºÊ¹ÓÃRedux×÷ΪӦÓÃ״̬¹ÜÀíÈÝÆ÷£¬Í³Ò»¹ÜÀíÓ¦ÓõÄ״̬Ê÷£¬ËüÍÆ´ÓÊý¾Ýµ¥Ò»¿ÉÐÅÀ´Ô´Ô­Ôò£¬ËùÓÐÊý¾Ý¶¼À´×Ôredux store£¬ËùÓеÄÊý¾Ý¸üÐÂÒ²¶¼ÓÉredux´¦Àí£»

2. redux store״̬Ê÷£ºredux¼¯ÖйÜÀíÓ¦ÓÃ״̬£¬×éÖ¯¹ÜÀíÐÎʽ¾ÍºÃ±ÈDOMÊ÷ºÍReact×é¼þÊ÷Ò»Ñù£¬ÒÔÊ÷µÄÐÎʽ×éÖ¯£¬¼òµ¥¸ßЧ£»

3. reduxºÍstore£ºreduxÊÇÒ»ÖÖFluxµÄʵÏÖ·½°¸£¬ËùÒÔ´´½¨ÁËstoreÒ»´Ê£¬ËüÀàËÆÓÚÉ̵꣬¼¯ÖйÜÀíÓ¦ÓÃ״̬£¬Ö§³Ö½«Ã¿Ò»¸ö·¢²¼µÄaction·Ö·¢ÖÁËùÓÐreducer£»

4. action£ºÒÔ¶ÔÏóÊý¾Ý¸ñʽ´æÔÚ£¬Í¨³£ÖÁÉÙÓÐtypeºÍpayloadÊôÐÔ£¬ËüÊǶÔreduxÖж¨ÒåµÄÈÎÎñµÄÃèÊö£»

5. reducer£ºÍ¨³£ÊÇÒÔº¯ÊýÐÎʽ´æÔÚ£¬½ÓÊÕstate£¨Ó¦Óþֲ¿×´Ì¬£©ºÍaction¶ÔÏóÁ½¸ö²ÎÊý£¬¸ù¾Ýaction.type(actionÀàÐÍ)Ö´Ðв»Í¬µÄÈÎÎñ£¬×ñÑ­º¯Êýʽ±à³Ì˼Ï룻

6. dispatch£ºstoreÌṩµÄ·Ö·¢actionµÄ¹¦ÄÜ·½·¨£¬´«µÝÒ»¸öaction¶ÔÏó²ÎÊý£»

7. createStore£º´´½¨storeµÄ·½·¨£¬½ÓÊÕreducer£¬³õʼӦÓÃ״̬£¬reduxÖмä¼þºÍÔöÇ¿Æ÷£¬³õʼ»¯store£¬¿ªÊ¼¼àÌýaction£»

Öмä¼þ£¨Redux Middleware£©

ReduxÖмä¼þ£¬ºÍNodeÖмä¼þÒ»Ñù£¬Ëü¿ÉÒÔÔÚaction·Ö·¢ÖÁÈÎÎñ´¦Àíreducer֮ǰ×öһЩ¶îÍ⹤×÷£¬dispatch·¢²¼µÄaction½«ÒÀ´Î´«µÝ¸øËùÓÐÖмä¼þ£¬×îÖÕµ½´ïreducer£¬ËùÒÔÎÒÃÇʹÓÃÖмä¼þ¿ÉÒÔÍØÕ¹ÖîÈç¼Ç¼ÈÕÖ¾£¬Ìí¼Ó¼à¿Ø£¬Çл»Â·Óɵȹ¦ÄÜ£¬ËùÒÔÖмä¼þ±¾ÖÊÉÏÖ»ÊÇÍØÕ¹ÁËstore.dispatch·½·¨¡£

ÔöÇ¿Æ÷£¨Store Enhancer£©

ÓÐЩʱºòÎÒÃÇ¿ÉÄܲ¢²»Âú×ãÓÚÍØÕ¹dispatch·½·¨£¬»¹Ï£ÍûÄÜÔöÇ¿store£¬reduxÌṩÒÔÔöÇ¿Æ÷ÐÎʽÔöÇ¿storeµÄ¸÷¸ö·½Ã棬ÉõÖÁ¿ÉÒÔÍêÈ«¶¨ÖÆÒ»¸östore¶ÔÏóÉϵÄËùÓнӿڣ¬¶ø²»½ö½öÊÇstore.dispatch·½·¨¡£

const logEnhancer = (createStore) => (reducer, preloadedState, enhancer) => {
const store = createStore(reducer, preloadedState, enhancer)
const originalDispatch = store.dispatch
store.dispatch = (action) => {
console.log(action)
originalDispatch(action)
}

return store
}

×î¼òµ¥µÄÀý×Ó´úÂëÈçÉÏ£¬Ðº¯Êý½ÓÊÕreduxµÄcreateStore·½·¨ºÍ´´½¨storeÐèÒªµÄ²ÎÊý£¬È»ºóÔÚº¯ÊýÄÚ²¿±£´æstore¶ÔÏóÉÏij·½·¨µÄÒýÓã¬ÖØÐÂʵÏָ÷½·¨£¬ÔÚÀïÃæ´¦ÀíÍêÔöÇ¿Âß¼­ºóµ÷ÓÃԭʼ·½·¨£¬±£Ö¤Ô­Ê¼¹¦ÄÜÕý³£Ö´ÐУ¬ÕâÑù¾ÍÔöÇ¿ÁËstoreµÄdispatch·½·¨¡£

¿ÉÒÔ¿´µ½£¬ÔöÇ¿Æ÷ÍêÈ«ÄÜʵÏÖÖмä¼þµÄ¹¦ÄÜ£¬Æäʵ£¬Öмä¼þ¾ÍÊÇÒÔÔöÇ¿Æ÷·½Ê½ÊµÏֵģ¬ËüÌṩµÄcompose·½·¨¾Í¿ÉÒÔ×éºÏ½«ÎÒÃÇ´«ÈëµÄÔöÇ¿Æ÷ÍØÕ¹µ½store£¬¶øÈç¹ûÎÒÃÇ´«ÈëÖмä¼þ£¬ÔòÐèÒªÏȵ÷ÓÃapplyMiddleware·½·¨°ü×°£¬ÄÚ²¿ÒÔÔöÇ¿Æ÷ÐÎʽ½«Öмä¼þ¹¦ÄÜÍØÕ¹µ½store.dispatch·½·¨

react-redux

ReduxÊÇÒ»¸ö¶ÀÁ¢µÄJavaScriptÓ¦ÓÃ״̬¹ÜÀíÈÝÆ÷¿â£¬Ëü¿ÉÒÔÓëReact¡¢Angular¡¢Ember¡¢jQueryÉõÖÁÔ­ÉúJavaScriptÓ¦ÓÃÅäºÏʹÓã¬ËùÒÔ¿ª·¢ReactÓ¦ÓÃʱ£¬ÐèÒª½«ReduxºÍReactÓ¦ÓÃÁ¬½ÓÆðÀ´£¬²ÅÄÜͳһʹÓÃRedux¹ÜÀíÓ¦ÓÃ״̬£¬Ê¹Óùٷ½ÌṩµÄreact-redux£¨https://github.com/reactjs/react-redux£©¿â¡£

class App extends Component {
render () {
const { store } = this.props
return (
<Provider store={store}>
<div>
<Routes />
</div>
</Provider>
)
}
}

react-redux¿âÌṩProvider×é¼þͨ¹ýcontext·½Ê½ÏòÓ¦ÓÃ×¢Èëstore£¬È»ºó¿ÉÒÔʹÓÃconnect¸ß½×·½·¨£¬»ñÈ¡²¢¼àÌýstore£¬È»ºó¸ù¾Ýstore stateºÍ×é¼þ×ÔÉíprops¼ÆËãµÃµ½ÐÂprops£¬×¢Èë¸Ã×é¼þ£¬²¢ÇÒ¿ÉÒÔͨ¹ý¼àÌýstore£¬±È½Ï¼ÆËã³öµÄÐÂpropsÅжÏÊÇ·ñÐèÒª¸üÐÂ×é¼þ¡£

¸ü¶à¹ØÓÚreact-reduxµÄÄÚÈÝ¿ÉÒÔÔĶÁ֮ǰµÄÎÄÕ£ºReact-Redux·ÖÎö

createStore

ʹÓÃreduxÌṩµÄcreateStore·½·¨´´½¨redux store£¬µ«ÊÇÔÚʵ¼ÊÏîÄ¿ÖÐÎÒÃdz£³£ÐèÒªÍØÕ¹reduxÌí¼ÓijЩ×Ô¶¨Ò幦ÄÜ»ò·þÎñ£¬ÈçÌí¼ÓreduxÖмä¼þ£¬Ìí¼ÓÒì²½ÈÎÎñ¹ÜÀísaga£¬ÔöÇ¿reduxµÈ£º

// creates the store
export default (rootReducer, rootSaga, initialState) => {
/* ------------- Redux Configuration ------------- */
// Middlewares
// Build the middleware for intercepting and dispatching navigation actions
const blogRouteMiddleware = routerMiddleware(history)
const sagaMiddleware = createSagaMiddleware()
const middleware = [blogRouteMiddleware, sagaMiddleware]

// enhancers
const enhancers = []
let composeEnhancers = compose

// create store
const store = createStore(
combineReducers({
router: routerReducer,
...reducers
}),
initialState,
composeEnhancers(
applyMiddleware(...middleware),
...enhancers
)
)
sagaMiddleware.run(saga)

return store;
}

reduxÓëImmutable

reduxĬÈÏÌṩÁËcombineReducers·½·¨ÕûºÏreduersÖÁredux£¬È»¶ø¸ÃĬÈÏ·½·¨ÆÚÍû½ÓÊÜÔ­ÉúJavaScript¶ÔÏó²¢ÇÒËü°Ñstate×÷ΪԭÉú¶ÔÏó´¦Àí£¬ËùÒÔµ±ÎÒÃÇʹÓÃcreateStore·½·¨²¢ÇÒ½ÓÊÜÒ»¸öImmutable¶ÔÏó×÷Ó¦Óóõʼ״̬ʱ£¬reducer½«»á·µ»ØÒ»¸ö´íÎó£¬Ô´´úÂëÈçÏ£º

if (!isPlainObject(inputState)) {
return (
`The ${argumentName} has unexpected type of "` + ({}).toString.call(inputState).match(/\s([a-z|A-Z]+)/)[1] +
".Expected argument to be an object with the following +
`keys:"${reducerKeys.join('", "')}"`
)
}

ÈçÉϱíÃ÷£¬Ô­Ê¼ÀàÐÍreducer½ÓÊܵÄstate²ÎÊýÓ¦¸ÃÊÇÒ»¸öÔ­ÉúJavaScript¶ÔÏó£¬ÎÒÃÇÐèÒª¶ÔcombineReducersÆä½øÐÐÔöÇ¿£¬ÒÔʹÆäÄÜ´¦ÀíImmutable¶ÔÏó£¬redux-immutable ¼´Ìṩ´´½¨Ò»¸ö¿ÉÒÔºÍImmutable.jsЭ×÷µÄRedux combineReducers¡£

import { combineReducers } from 'redux-immutable';
import Immutable from 'immutable';
import configureStore from './CreateStore';

// use Immutable.Map to create the store state tree
const initialState = Immutable.Map();

export default () => {
// Assemble The Reducers
const rootReducer = combineReducers({
...RouterReducer,
...AppReducer
});

return configureStore(rootReducer, rootSaga, initialState);
}

ÈçÉÏ´úÂ룬¿ÉÒÔ¿´¼ûÎÒÃÇ´«ÈëµÄinitialStateÊÇÒ»¸öImmutable.MapÀàÐÍÊý¾Ý£¬ÎÒÃǽ«reduxÕû¸östateÊ÷´Ô¸ùÔ´¿ªÊ¼Immutable»¯£¬ÁíÍâ´«ÈëÁË¿ÉÒÔ´¦ÀíImmutable stateµÄreducersºÍsagas¡£

ÁíÍâÿһ¸östateÊ÷½ÚµãÊý¾Ý¶¼ÊÇImmutable½á¹¹£¬ÈçAppReducer£º

const initialState = Immutable.fromJS({
ids: [],
posts: {
list: [],
total: 0,
totalPages: 0
}
})

const AppReducer = (state = initialState, action) => {
case 'RECEIVE_POST_LIST':
const newState = state.merge(action.payload)
return newState || state
default:
return state
}

ÕâÀïĬÈÏʹÓÃImmutable.fromJS()·½·¨×´Ì¬Ê÷½Úµã¶ÔÏóת»¯ÎªImmutable½á¹¹£¬²¢ÇÒ¸üÐÂstateʱʹÓÃImmutable·½·¨state.merge()£¬±£Ö¤×´Ì¬Í³Ò»¿ÉÔ¤²â¡£

React·ÓÉ

ÔÚReact webµ¥Ò³ÃæÓ¦ÓÃÖУ¬Ò³Ãæ¼¶UI×é¼þµÄչʾºÍÇл»ÍêÈ«ÓÉ·ÓÉ¿ØÖÆ£¬Ã¿Ò»¸ö·Óɶ¼ÓжÔÓ¦µÄURL¼°Â·ÓÉÐÅÏ¢£¬ÎÒÃÇ¿ÉÒÔͨ¹ý·ÓÉͳһ¸ßЧµÄ¹ÜÀíÎÒÃǵÄ×é¼þÇл»£¬±£³ÖUIÓëURLͬ²½£¬±£Ö¤Ó¦ÓõÄÎȶ¨ÐÔ¼°ÓѺÃÌåÑé¡£

react-router

React RouterÊÇÍêÕûµÄReact ·Óɽâ¾ö·½°¸£¬Ò²ÊÇ¿ª·¢ReactÓ¦ÓÃ×ʹÓõÄ·ÓɹÜÀí¿â£¬Ö»ÒªÓùýËü£¬¾ø¶Ô»áϲ»¶ÉÏËüµÄÉè¼Æ£¬ËüÌṩ¼òµ¥µÄAPI£¬ÒÔÉùÃ÷ʽ·½Ê½ÊµÏÖÇ¿´óµÄ·Óɹ¦ÄÜ£¬ÖîÈç°´Ðè¼ÓÔØ£¬¶¯Ì¬Â·Óɵȡ£

1. ÉùÃ÷ʽ£ºÓï·¨¼ò½à£¬ÇåÎú£»

2. °´Ðè¼ÓÔØ£ºÑÓ³Ù¼ÓÔØ£¬¸ù¾ÝʹÓÃÐèÒªÅжÏÊÇ·ñÐèÒª¼ÓÔØ£»

3. ¶¯Ì¬Â·ÓÉ£º¶¯Ì¬×éºÏÓ¦Ó÷Óɽṹ£¬¸üÁé»î£¬¸ü·ûºÏ×é¼þ»¯¿ª·¢Ä£Ê½£»

¶¯Ì¬Â·ÓÉÓ뾲̬·ÓÉ

ʹÓÃreact-router v4°æ±¾¿ÉÒÔ¶¨Òå¿çƽ̨µÄÓ¦Óö¯Ì¬Â·Óɽṹ£¬ËùνµÄ¶¯Ì¬Â·ÓÉ£¨Dynamic Routing£©¼´ÔÚäÖȾ¹ý³ÌÖз¢Éú·ÓɵÄÇл»£¬¶ø²»ÐèÒªÔÚ´´½¨Ó¦ÓÃǰ¾ÍÅäÖúã¬ÕâÒ²ÕýÊÇÆäÇø±ðÓÚ¾²Ì¬Â·ÓÉ£¨Static Routing£©ËùÔÚ£¬¶¯Ì¬Â·ÓÉÌá¸ß¸üÁé»îµÄ·ÓÉ×éÖ¯·½Ê½£¬¶øÇÒ¸ü·½±ã±àÂëʵÏÖ·Óɰ´Ðè¼ÓÔØ×é¼þ¡£

ÔÚreact-router v2ºÍv3°æ±¾ÖУ¬¿ª·¢ReactÓ¦ÓÃÐèÒªÔÚ¿ªÊ¼äÖȾǰ¾Í¶¨ÒåºÃÍêÕûµÄÓ¦Ó÷Óɽṹ£¬ËùÓеÄ·Óɶ¼ÐèҪͬʱ³õʼ»¯£¬²ÅÄÜÔÚÓ¦ÓÃäÖȾºóÉúЧ£¬»á²úÉúºÜ¶àǶÌ×»¯Â·ÓÉ£¬É¥Ê§Á˶¯Ì¬Â·ÓɵÄÁé»îÐԺͼò½àµÄ°´Ðè¼ÓÔØ±àÂ뷽ʽ¡£

react-router v4.x

ÔÚreact-router 2.xºÍ3.x°æ±¾ÖУ¬¶¨ÒåÒ»¸öÓ¦Ó÷Óɽṹͨ³£ÈçÏ£º

import React from 'react'
import ReactDOM from 'react-dom'
import { browserHistory, Router, Route, IndexRoute } from 'react-router'

import App from '../components/App'
import Home from '../components/Home'
import About from '../components/About'
import Features from '../components/Features'

ReactDOM.render(
<Router history={browserHistory}>
<Route path='/' component={App}>
<IndexRoute component={Home} />
<Route path='about' component={About} />
<Route path='features' component={Features} />
</Route>
</Router>,
document.getElementById('app')
)

ºÜ¼òµ¥£¬µ«ÊÇËùÓеÄ·Óɽṹ¶¼ÐèÒªÔÚäÖȾӦÓÃǰ£¬Í³Ò»¶¨Ò壬²ã²ãǶÌ×£»¶øÇÒÈç¹ûҪʵÏÖÒì²½°´Ðè¼ÓÔØ»¹ÐèÒªÔÚÕâÀï¶Ô·ÓÉÅäÖöÔÏó½øÐÐÐ޸ģ¬Ê¹ÓÃgetComponentAPI£¬²¢ÇÖÈë¸ÄÔì¸Ã×é¼þ£¬ÅäºÏwebpackµÄÒì²½´ò°ü¼ÓÔØAPI£¬ÊµÏÖ°´Ðè¼ÓÔØ£º

1. ·Óɲã²ãǶÌ×£¬±ØÐëÔÚäÖȾӦÓÃǰͳһÉùÃ÷£»

2. API²»Í¬£¬ÐèҪʹÓÃgetComponent£¬Ôö¼Ó·ÓÉÅäÖöÔÏóµÄ¸´ÔÓÐÔ£»

3. <Route>Ö»ÊÇÒ»¸öÉùÃ÷·Óɵĸ¨Öú±êÇ©£¬±¾ÉíÎÞÒâÒ壻

¶øÊ¹ÓÃreact-router v4.xÔòÈçÏ£º

// react-dom (what we'll use here)
import { BrowserRouter } from 'react-router-dom'

ReactDOM.render((
<BrowserRouter>
<App/>
</BrowserRouter>
), el)

const App = () => (
<div>
<nav>
<Link to="/about">Dashboard</Link>
</nav>
<Home />
<div>
<Route path="/about" component={About}/>
<Route path="/features" component={Features}/>
</div>
</div>
)

Ïà±È֮ǰ°æ±¾£¬¼õÉÙÁËÅäÖû¯µÄºÛ¼££¬¸ü͹ÏÔÁË×é¼þ»¯µÄ×éÖ¯·½Ê½£¬¶øÇÒÔÚäÖȾ×é¼þʱ²ÅʵÏָò¿·Ö·ÓÉ£¬¶øÈç¹ûÆÚÍû°´Ðè¼ÓÔØ¸Ã×é¼þ£¬Ôò¿ÉÒÔͨ¹ý·âװʵÏÖÒ»¸öÖ§³ÖÒì²½¼ÓÔØ×é¼þµÄ¸ß½××é¼þ£¬½«¾­¹ý¸ß½××é¼þ´¦Àíºó·µ»ØµÄ×é¼þ´«Èë<Route>¼´¿É£¬ÒÀÈ»×ñÑ­×é¼þ»¯ÐÎʽ£º

1. Áé»îÐÔ£ºÂ·ÓÉ¿ÉÒÔÔÚäÖȾ×é¼þÖÐÉùÃ÷£¬²»ÐèÒÀÀµÓÚÆäËû·ÓÉ£¬²»ÐèÒª¼¯ÖÐÅäÖã»

2. ¼ò½à£ºÍ³Ò»´«Èëcomponent£¬±£Ö¤Â·ÓÉÉùÃ÷µÄ¼ò½àÐÔ£»

3. ×é¼þ»¯£º<Route>×÷Ϊһ¸öÕæÊµ×é¼þ´´½¨Â·ÓÉ£¬¿ÉÒÔäÖȾ£»

·Óɹ³×Ó·½·¨

ÁíÍâÐèҪעÒâµÄÊÇ£¬Ïà¶ÔÓÚ֮ǰ°æ±¾ÌṩonEnter, onUpdate, onLeaveµÈ¹³×Ó·½·¨APIÔÚÒ»¶¨³Ì¶ÈÉÏÌá¸ßÁ˶Ô·ÓɵĿɿØÐÔ£¬µ«ÊÇʵÖÊÖ»ÊǸ²¸ÇÁËäÖȾ×é¼þµÄÉúÃüÖÜÆÚ·½·¨£¬ÏÖÔÚÎÒÃÇ¿ÉÒÔͨ¹ý·ÓÉäÖȾ×é¼þµÄÉúÃüÖÜÆÚ·½·¨Ö±½Ó¿ØÖÆÂ·ÓÉ£¬ÈçʹÓÃcomponentDidMount »ò componentWillMount ´úÌæ onEnter¡£

·ÓÉÓëRedux

ͬʱʹÓÃReact-RouterºÍReduxʱ£¬´ó¶àÊýÇé¿öÊÇÕý³£µÄ£¬µ«ÊÇÒ²¿ÉÄܳöÏÖ·Óɱä¸ü×é¼þδ¸üеÄÇé¿ö£¬È磺

1. ÎÒÃÇʹÓÃreduxµÄconnect·½·¨½«×é¼þÁ¬½ÓÖÁredux£ºconnect(Home);

2. ×é¼þ²»ÊÇÒ»¸ö·ÓÉäÖȾ×é¼þ£¬¼´²»ÊÇʹÓÃRoute>×é¼þÐÎʽ£º<Route component={Home} />ÉùÃ÷äÖȾµÄ£»

ÕâÊÇÎªÊ²Ã´ÄØ£¿£¬ÒòΪRedux»áʵÏÖ×é¼þµÄshouldComponentUpdate·½·¨£¬µ±Â·Óɱ仯ʱ£¬¸Ã×é¼þ²¢Ã»ÓнÓÊÕµ½props±íÃ÷·¢ÉúÁ˱ä¸ü£¬ÐèÒª¸üÐÂ×é¼þ¡£

ÄÇôÈçºÎ½â¾öÎÊÌâÄØ£¿£¬Òª½â¾öÕâ¸öÎÊÌâÖ»ÐèÒª¼òµ¥µÄʹÓÃreact-router-domÌṩµÄwithRouter·½·¨°ü¹ü×é¼þ£º


import { withRouter } from 'react-router-dom'
export default withRouter(connect(mapStateToProps)(Home))

ReduxÕûºÏ

ÔÚʹÓÃReduxÒÔºó£¬ÐèÒª×ñÑ­reduxµÄÔ­Ôò£ºµ¥Ò»¿ÉÐÅÊý¾ÝÀ´Ô´£¬¼´ËùÓÐÊý¾ÝÀ´Ô´¶¼Ö»ÄÜÊÇreudx store£¬react·ÓÉ״̬Ҳ²»Ó¦ÀýÍ⣬ËùÒÔÐèÒª½«Â·ÓÉstateÓëstore stateÁ¬½Ó¡£

react-router-redux

Á¬½ÓReact RouterÓëRedux£¬ÐèҪʹÓÃreact-router-redux¿â£¬¶øÇÒreact-router v4°æ±¾ÐèÒªÖ¸¶¨°²×°@next°æ±¾ºÍhsitory¿â£º

yarn add react-router-redux@next
yarn add history

È»ºó£¬ÔÚ´´½¨storeʱ£¬ÐèҪʵÏÖÈçÏÂÅäÖãº

1. ´´½¨Ò»¸öhistory¶ÔÏ󣬶ÔÓÚwebÓ¦Óã¬ÎÒÃÇÑ¡ÔñbrowserHisotry£¬¶ÔÓ¦ÐèÒª´Óhistory/createBrowserHistoryÄ£¿éÒýÈëcreateHistory·½·¨ÒÔ´´½¨history¶ÔÏó£»

µã´Ë²é¿´¸ü¶àhistoryÏà¹ØÄÚÈÝ£¨https://reacttraining.com/react-router/web/api/history£©

2. Ìí¼ÓrouterReducerºÍrouterMiddlewareÖмä¼þ¡°£¬ÆäÖÐrouterMiddlewareÖмä¼þ½ÓÊÕhistory¶ÔÏó²ÎÊý£¬Á¬½ÓstoreºÍhistory£¬µÈͬÓھɰ汾µÄsyncHistoryWithStore£»

import createHistory from 'history/createBrowserHistory'
import { ConnectedRouter, routerReducer, routerMiddleware, push } from 'react-router-redux'
// Create a history of your choosing (we're using a browser history in this case)
export const history = createHistory()

// Build the middleware for intercepting and dispatching navigation actions
const middleware = routerMiddleware(history)

// Add the reducer to your store on the `router` key
// Also apply our middleware for navigating
const store = createStore(
combineReducers({
...reducers,
router: routerReducer
}),
applyMiddleware(middleware)
)

return store

ÔÚäÖȾ¸ù×é¼þʱ£¬ÎÒÃdzéÏó³öÁ½¸ö×é¼þ£º

1. ³õʼ»¯äÖȾ¸ù×é¼þ£¬¹ÒÔØÖÁDOMµÄ¸ù×é¼þ£¬ÓÉ<Provider>×é¼þ°ü¹ü£¬×¢Èëstore£»

2. ·ÓÉÅäÖÃ×é¼þ£¬ÔÚ¸ù×é¼þÖУ¬ÉùÃ÷·ÓÉÅäÖÃ×é¼þ£¬³õʼ»¯±ØÒªµÄÓ¦Ó÷Óɶ¨Ò弰·ÓɶÔÏó

import createStore from './store/'
import Routes from './routes/'
import appReducer from './store/appRedux'

const store = createStore({}, {
app: appReducer
})

/**
* ÏîÄ¿¸ù×é¼þ
* @class App
* @extends Component
*/
class App extends Component {
render () {
const { store } = this.props

return (
<Provider store={store}>
<div>
<Routes />
</div>
</Provider>
)
}
}

// äÖȾ¸ù×é¼þ
ReactDOM.render(
<App store={store} />,
document.getElementById('app')
)

ÉÏÃæµÄ<Routes>×é¼þÊÇÏîÄ¿µÄ·ÓÉ×é¼þ£º

import { history } from '../store/'
import { ConnectedRouter } from 'react-router-redux'
import { Route } from 'react-router'

class Routes extends Component {
render () {
return (
<ConnectedRouter history={history}>
<div>
<BlogHeader />
<div>
<Route exact path='/' component={Home} />
<Route exact path='/posts/:id' component={Article} />
</div>
</div>
</ConnectedRouter>
)
}
}

Ê×ÏÈʹÓÃreact-router-reduxÌṩµÄConnectedRouter×é¼þ°ü¹ü·ÓÉÅäÖ㬸Ã×é¼þ½«×Ô¶¯Ê¹ÓÃ<Provider>×é¼þ×¢ÈëµÄstore£¬ÎÒÃÇÐèÒª×öµÄÊÇÊÖ¶¯´«ÈëhistoryÊôÐÔ£¬ÔÚ×é¼þÄÚ»áµ÷ÓÃhistory.listen·½·¨¼àÌýä¯ÀÀÆ÷LOCATION_CHANGEʼþ£¬×îºó·µ»Øreact-routerµÄ<Router >×é¼þ£¬´¦Àí×÷Ϊthis.props.children´«ÈëµÄ·ÓÉÅäÖã¬ConnectedRouter×é¼þÄÚÈÝ´«ËÍ

dispatchÇл»Â·ÓÉ

ÅäÖÃÉÏÃæ´úÂëºó£¬¾ÍÄܹ»ÒÔdispatch actionµÄ·½Ê½´¥·¢Â·ÓÉÇл»ºÍ×é¼þ¸üÐÂÁË£º

import { push } from 'react-router-redux'
// Now you can dispatch navigation actions from anywhere!
store.dispatch(push('/about'))

Õâ¸öreducerËù×öµÄÖ»Êǽ«Appµ¼º½Â·ÓÉ״̬ºÏ²¢Èëstore¡£

redux³Ö¾Ã»¯

ÎÒÃÇÖªµÀä¯ÀÀÆ÷ĬÈÏÓÐ×ÊÔ´µÄ»º´æ¹¦Äܲ¢ÇÒÌṩ±¾µØ³Ö¾Ã»¯´æ´¢·½Ê½ÈçlocalStorage£¬indexDb£¬webSQLµÈ£¬Í¨³£¿ÉÒÔ½«Ä³Ð©Êý¾Ý´æ´¢ÔÚ±¾µØ£¬ÔÚÒ»¶¨ÖÜÆÚÄÚ£¬µ±Óû§ÔٴηÃÎÊʱ£¬Ö±½Ó´Ó±¾µØ»Ö¸´Êý¾Ý£¬¿ÉÒÔ¼«´óÌá¸ßÓ¦ÓÃÆô¶¯ËÙ¶È£¬Óû§ÌåÑé¸üÓÐÓÅÊÆ£¬ÎÒÃÇ¿ÉÒÔʹÓÃlocalStorage´æ´¢Ò»Ð©Êý¾Ý£¬Èç¹ûÊǽϴóÁ¿Êý¾Ý´æ´¢¿ÉÒÔʹÓÃwebSQL¡£

ÁíÍⲻͬÓÚÒÔÍùµÄÖ±½Ó´æ´¢Êý¾Ý£¬Æô¶¯Ó¦ÓÃʱ±¾µØ¶ÁȡȻºó»Ö¸´Êý¾Ý£¬¶ÔÓÚreduxÓ¦ÓöøÑÔ£¬Èç¹ûÖ»ÊÇ´æ´¢Êý¾Ý£¬ÄÇôÎÒÃǾ͵ÃΪÿһ¸öreducerÍØÕ¹£¬µ±ÔÙ´ÎÆô¶¯Ó¦ÓÃʱȥ¶ÁÈ¡³Ö¾Ã»¯µÄÊý¾Ý£¬ÕâÊDZȽϷ±Ëö¶øÇÒµÍЧµÄ·½Ê½£¬ÊÇ·ñ¿ÉÒÔ³¢ÊÔ´æ´¢reducer key£¬È»ºó¸ù¾Ýkey»Ö¸´¶ÔÓ¦µÄ³Ö¾Ã»¯Êý¾Ý£¬Ê×ÏÈ×¢²áRehydrate reducer£¬µ±´¥·¢actionʱ¸ù¾ÝÆäreducer key»Ö¸´Êý¾Ý£¬È»ºóÖ»ÐèÒªÔÚÓ¦ÓÃÆô¶¯Ê±·Ö·¢action£¬ÕâÒ²ºÜÈÝÒ׳éÏó³É¿ÉÅäÖõÄÍØÕ¹·þÎñ£¬Êµ¼ÊÉÏÈý·½¿âredux-persist£¨https://github.com/rt2zz/redux-persist£©ÒѾ­ÎªÎÒÃÇ×öºÃÁËÕâÒ»ÇС£

redux-persist

ҪʵÏÖreduxµÄ³Ö¾Ã»¯£¬°üÀ¨redux storeµÄ±¾µØ³Ö¾Ã»¯´æ´¢¼°»Ö¸´Æô¶¯Á½¸ö¹ý³Ì£¬Èç¹ûÍêÈ«×Ô¼º±àдʵÏÖ£¬´úÂëÁ¿±È½Ï¸´ÔÓ£¬¿ÉÒÔʹÓÿªÔ´¿âredux-persist£¬ËüÌṩpersistStoreºÍautoRehydrate·½·¨·Ö±ð³Ö¾Ã»¯±¾µØ´æ´¢store¼°»Ö¸´Æô¶¯store£¬ÁíÍ⻹֧³Ö×Ô¶¨Òå´«Èë³Ö¾Ã»¯¼°»Ö¸´storeʱ¶Ôstore stateµÄת»»ÍØÕ¹¡£

yarn add redux-persist

³Ö¾Ã»¯store

ÈçÏÂÔÚ´´½¨storeʱ»áµ÷ÓÃpersistStoreÏà¹Ø·þÎñ-RehydrationServices.updateReducers()£º

// configure persistStore and check reducer version number
if (ReduxPersistConfig.active) {
RehydrationServices.updateReducers(store);
}

¸Ã·½·¨ÄÚʵÏÖÁËstoreµÄ³Ö¾Ã»¯´æ´¢£º

// Check to ensure latest reducer version
storage.getItem('reducerVersion').then((localVersion) => {
if (localVersion !== reducerVersion) {
// Çå¿Õ store
persistStore(store, null, startApp).purge();
storage.setItem('reducerVersion', reducerVersion);
} else {
persistStore(store, null, startApp);
}
}).catch(() => {
persistStore(store, null, startApp);
storage.setItem('reducerVersion', reducerVersion);
})

»áÔÚlocalStorage´æ´¢Ò»¸öreducer°æ±¾ºÅ£¬Õâ¸öÊÇÔÚÓ¦ÓÃÅäÖÃÎļþÖпÉÒÔÅäÖã¬Ê×´ÎÖ´Ðг־û¯Ê±´æ´¢¸Ã°æ±¾ºÅ¼°store£¬Èôreducer°æ±¾ºÅ±ä¸üÔòÇå¿ÕÔ­À´´æ´¢µÄstore£¬·ñÔò´«Èëstore¸ø³Ö¾Ã»¯·½·¨persistStore¼´¿É¡£

persistStore(store, [config], [callback])

¸Ã·½·¨Ö÷ҪʵÏÖstoreµÄ³Ö¾Ã»¯ÒÔ¼°·Ö·¢rehydration action :

1. ¶©ÔÄ redux store£¬µ±Æä·¢Éú±ä»¯Ê±´¥·¢store´æ´¢²Ù×÷£»

2. ´ÓÖ¸¶¨µÄStorageEngine£¨ÈçlocalStorage£©ÖлñÈ¡Êý¾Ý£¬½øÐÐת»»£¬È»ºóͨ¹ý·Ö·¢ REHYDRATE action£¬´¥·¢ REHYDRATE ¹ý³Ì£»

½ÓÊÕ²ÎÊýÖ÷ÒªÈçÏ£º

1. store: ³Ö¾Ã»¯µÄstore£»

2. config£ºÅäÖöÔÏó

a. storage£ºÒ»¸ö ³Ö¾Ã»¯ÒýÇæ£¬ÀýÈç LocalStorage ºÍ AsyncStorage£»

b. transforms£º ÔÚ rehydration ºÍ storage ½×¶Î±»µ÷ÓõÄת»»Æ÷£»

c. blacklist£º ºÚÃûµ¥Êý×飬ָ¶¨³Ö¾Ã»¯ºöÂ﵀ reducers µÄ key£»

3. callback£ºehydration ²Ù×÷½áÊøºóµÄ»Øµ÷£»

»Ö¸´Æô¶¯

ºÍpersisStoreÒ»Ñù£¬ÒÀÈ»ÊÇÔÚ´´½¨redux storeʱ³õʼ»¯×¢²árehydrateÍØÕ¹£º

// add the autoRehydrate enhancer
if (ReduxPersist.active) {
enhancers.push(autoRehydrate());
}

¸Ã·½·¨ÊµÏֵŦÄܼܺòµ¥£¬¼´Ê¹Óà ³Ö¾Ã»¯µÄÊý¾Ý»Ö¸´(rehydrate) store ÖÐÊý¾Ý£¬ËüÆäʵÊÇ×¢²áÁËÒ»¸öautoRehydarte reducer£¬»á½ÓÊÕǰÎÄpersistStore·½·¨·Ö·¢µÄrehydrate action£¬È»ºóºÏ²¢state¡£

µ±È»£¬autoRehydrate²»ÊDZØÐëµÄ£¬ÎÒÃÇ¿ÉÒÔ×Ô¶¨Òå»Ö¸´store·½Ê½£º

import {REHYDRATE} from 'redux-persist/constants';

//...
case REHYDRATE:
const incoming = action.payload.reducer
if (incoming) {
return {
...state,
...incoming
}
}
return state;

°æ±¾¸üÐÂ

ÐèҪעÒâµÄÊÇredux-persist¿âÒѾ­·¢²¼µ½v5.x£¬¶ø±¾ÎĽéÉܵÄÒÔv5.xΪÀý£¬v4.x£¨https://github.com/rt2zz/redux-persist/tree/f4a6e86c66693a0bd5e6ea73043fd98b14f44a96£©²Î¿¼´Ë´¦£¬Ð°汾ÓÐһЩ¸üУ¬¿ÉÒÔÑ¡ÔñÐÔ¾ö¶¨Ê¹ÓÃÄĸö°æ±¾£¬ÏêϸÇëµã»÷²é¿´£¨https://github.com/rt2zz/redux-persist/releases£©¡£

³Ö¾Ã»¯ÓëImmutable

Ç°ÃæÒѾ­Ìáµ½ReduxÓëImmutableµÄÕûºÏ£¬ÉÏÎÄʹÓõÄredux -persistĬÈÏÒ²Ö»ÄÜ´¦ÀíÔ­ÉúJavaScript¶ÔÏóµÄredux store state£¬ËùÒÔÐèÒªÍØÕ¹ÒÔ¼æÈÝImmutable¡£

redux-persist-immutable

ʹÓÃredux-persist-immutable£¨https://github.com/rt2zz/redux-persist-immutable£©¿â¿ÉÒÔºÜÈÝÒ×ʵÏÖ¼æÈÝ£¬Ëù×öµÄ½ö½öÊÇʹÓÃÆäÌṩµÄpersistStore·½·¨Ìæ»»redux-persistËùÌṩµÄ·½·¨£º

import { persistStore } from 'redux-persist-immutable';

transform

ÎÒÃÇÖªµÀ³Ö¾Ã»¯storeʱ£¬Õë¶ÔµÄ×îºÃÊÇÔ­ÉúJavaScript¶ÔÏó£¬ÒòΪͨ³£Immutable½á¹¹Êý¾ÝÓкܶศÖúÐÅÏ¢£¬²»Ò×ÓÚ´æ´¢£¬ËùÒÔÐèÒª¶¨Òå³Ö¾Ã»¯¼°»Ö¸´Êý¾ÝʱµÄת»»²Ù×÷£º

import R from 'ramda';
import Immutable, { Iterable } from 'immutable';

// change this Immutable object into a JS object
const convertToJs = (state) => state.toJS();

// optionally convert this object into a JS object if it is Immutable
const fromImmutable = R.when(Iterable.isIterable, convertToJs);

// convert this JS object into an Immutable object
const toImmutable = (raw) => Immutable.fromJS(raw);

// the transform interface that redux-persist is expecting
export default {
out: (state) => {
return toImmutable(state);
},
in: (raw) => {
return fromImmutable(raw);
}
};

ÈçÉÏ£¬Êä³ö¶ÔÏóÖеÄinºÍout·Ö±ð¶ÔÓ¦³Ö¾Ã»¯¼°»Ö¸´Êý¾ÝʱµÄת»»²Ù×÷£¬ÊµÏÖµÄÖ»ÊÇʹÓÃfromJS()ºÍtoJS()ת»»JsºÍImmutableÊý¾Ý½á¹¹£¬Ê¹Ó÷½Ê½ÈçÏ£º

import immutablePersistenceTransform from '../services/ImmutablePersistenceTransform'
persistStore(store, {
transforms: [immutablePersistenceTransform]
}, startApp);

ÔÚÏîÄ¿ÖÐÒýÈëImmutableÒÔºó£¬ÐèÒª¾¡Á¿±£Ö¤ÒÔϼ¸µã£º

1. redux storeÕû¸östateÊ÷µÄͳһImmutable»¯£»

2. redux³Ö¾Ã»¯¶ÔImmutableÊý¾ÝµÄ¼æÈÝ£»

3. React·ÓɼæÈÝImmutable£»

¹ØÓÚImmutable¼°Redux£¬ReselectµÈµÄʵ¼ù¿¼Ñé²é¿´Ö®Ç°Ð´µÄһƪÎÄÕ£ºImmutable.jsÓëReact,Redux¼°reselectµÄʵ¼ù£¨http://blog.codingplayboy.com/2017/09/14/immutable-react-redux/£©¡£

ImmutableÓëReact·ÓÉ

Ç°ÃæÁ½µãÒѾ­ÔÚÇ°ÃæÁ½½Ú²ûÊö¹ý£¬µÚÈýµãreact-router¼æÈÝImmutable£¬Æäʵ¾ÍÊÇʹӦÓ÷ÓÉ״̬¼æÈÝImmutable£¬ÔÚReact·ÓÉÒ»½ÚÒѾ­½éÉÜÈçºÎ½«React·ÓÉ״̬Á¬½ÓÖÁRedux store£¬µ«ÊÇÈç¹ûÓ¦ÓÃʹÓÃÁËImmutable¿â£¬Ôò»¹ÐèÒª¶îÍâ´¦Àí£¬½«react-router stateת»»ÎªImmutable¸ñʽ£¬routeReducer²»ÄÜ´¦ÀíImmutable£¬ÎÒÃÇÐèÒª×Ô¶¨ÒåÒ»¸öеÄRouterReducer£º

import Immutable from 'immutable';
import { LOCATION_CHANGE } from 'react-router-redux';

const initialState = Immutable.fromJS({
location: null
});

export default (state = initialState, action) => {
if (action.type === LOCATION_CHANGE) {
return state.set('location', action.payload);
}

return state;
};

½«Ä¬Èϳõʼ·ÓÉ״̬ת»»ÎªImmutable£¬²¢ÇÒ·Óɱä¸üʱʹÓÃImmutable API²Ù×÷state¡£

seamless-Immutable

µ±ÒýÈëImmutable.jsºó£¬¶ÔÓ¦ÓÃ״̬Êý¾Ý½á¹¹µÄʹÓÃAPI¾ÍµÃ×ñÑ­Immutable API£¬¶ø²»ÄÜÔÙʹÓÃÔ­ÉúJavaScript¶ÔÏó£¬Êý×éµÈµÄ²Ù×÷APIÁË£¬ÖîÈ磬Êý×é½â¹¹£¨[a, b] = [b, c]£©£¬¶ÔÏóÍØÕ¹·û£¨¡­£©µÈ£¬´æÔÚһЩÎÊÌ⣺

1. ImmutableÊý¾Ý¸¨Öú½Úµã½Ï¶à£¬Êý¾Ý½Ï´ó£º

2. ±ØÐëʹÓÃImmutableÓï·¨£¬ºÍJavaScriptÓï·¨ÓвîÒ죬²»ÄܺܺõļæÈÝ£»

3. ºÍRedux£¬react-routerµÈJavaScript¿âдЭ×÷ʱ£¬ÐèÒªÒýÈë¶îÍâµÄ¼æÈÝ´¦Àí¿â£»

Õë¶ÔÕâЩÎÊÌ⣬ÉçÇøÓÐÁËseamless-immutable¿É¹©Ì滻ѡÔñ£º

1. ¸üÇ᣺Ïà¶ÔÓÚImmutable.jsseamless-immutable¿â¸üÇáС£»

2. Óï·¨£º¶ÔÏóºÍÊý×éµÄ²Ù×÷Óï·¨¸üÌù½üÔ­ÉúJavaScript£»

3. ºÍÆäËûJavaScript¿âЭ×÷¸ü·½±ã£»

Òì²½ÈÎÎñÁ÷¹ÜÀí

×îºóÒª½éÉܵÄÄ£¿éÊÇÒì²½ÈÎÎñ¹ÜÀí£¬ÔÚÓ¦Óÿª·¢¹ý³ÌÖУ¬×îÖ÷ÒªµÄÒì²½ÈÎÎñ¾ÍÊÇÊý¾ÝHTTPÇëÇó£¬ËùÒÔÎÒÃǽ²Òì²½ÈÎÎñ¹ÜÀí£¬Ö÷Òª¹Ø×¢ÔÚÊý¾ÝHTTPÇëÇóµÄÁ÷³Ì¹ÜÀí¡£

axios

±¾ÏîÄ¿ÖÐʹÓÃaxios£¨https://github.com/axios/axios£©×÷ΪHTTPÇëÇó¿â£¬axiosÊÇÒ»¸öPromise¸ñʽµÄHTTP¿Í»§¶Ë£¬Ñ¡Ôñ´Ë¿âµÄÔ­ÒòÖ÷ÒªÓÐÒÔϼ¸µã£º

1. ÄÜÔÚä¯ÀÀÆ÷·¢ÆðXMLHttpRequest£¬Ò²ÄÜÔÚnode.js¶Ë·¢ÆðHTTPÇëÇó£»

2. Ö§³ÖPromise£»

3. ÄÜÀ¹½ØÇëÇóºÍÏìÓ¦£»

4. ÄÜÈ¡ÏûÇëÇó£»

5. ×Ô¶¯×ª»»JSONÊý¾Ý£»

redux-saga

redux-sagaÊÇÒ»¸öÖÂÁ¦ÓÚʹӦÓÃÖÐÈçÊý¾Ý»ñÈ¡£¬±¾µØ»º´æ·ÃÎʵÈÒì²½ÈÎÎñÒ×ÓÚ¹ÜÀí£¬¸ßЧÔËÐУ¬±ãÓÚ²âÊÔ£¬ÄܸüºÃµÄ´¦ÀíÒì³£µÄÈý·½¿â¡£

Redux-sagaÊÇÒ»¸öreduxÖмä¼þ£¬Ëü¾ÍÏñÓ¦ÓÃÖÐÒ»¸öµ¥¶ÀµÄ½ø³Ì£¬Ö»¸ºÔð¹ÜÀíÒì²½ÈÎÎñ£¬Ëü¿ÉÒÔ½ÓÊÜÓ¦ÓÃÖ÷½ø³ÌµÄredux actionÒÔ¾ö¶¨Æô¶¯£¬ÔÝÍ£»òÕßÊÇÈ¡Ïû½ø³ÌÈÎÎñ£¬ËüÒ²¿ÉÒÔ·ÃÎÊreduxÓ¦ÓÃstore state£¬È»ºó·Ö·¢action¡£

³õʼ»¯saga

redux-sagaÊÇÒ»¸öÖмä¼þ£¬ËùÒÔÊ×Ïȵ÷ÓÃcreateSagaMiddleware·½·¨´´½¨Öмä¼þ£¬È»ºóʹÓÃreduxµÄapplyMiddleware·½·¨ÆôÓÃÖмä¼þ£¬Ö®ºóʹÓÃcompose¸¨Öú·½·¨´«¸øcreateStore´´½¨store£¬×îºóµ÷ÓÃrun·½·¨Æô¶¯¸ùsaga£º

import { createStore, applyMiddleware, compose } from 'redux';
import createSagaMiddleware from 'redux-saga';
import rootSaga from '../sagas/'

const sagaMiddleware = createSagaMiddleware({ sagaMonitor });
middleware.push(sagaMiddleware);
enhancers.push(applyMiddleware(...middleware));

const store = createStore(rootReducer, initialState, compose(...enhancers));

// kick off root saga
sagaMiddleware.run(rootSaga);

saga·ÖÁ÷

ÔÚÏîÄ¿ÖÐͨ³£»áÓкܶಢÁÐÄ£¿é£¬Ã¿¸öÄ£¿éµÄsagaÁ÷Ò²Ó¦¸ÃÊDz¢Áеģ¬ÐèÒªÒÔ¶à·ÖÖ§ÐÎʽ²¢ÁУ¬redux-sagaÌṩµÄfork·½·¨¾ÍÊÇÒÔпª·ÖÖ§µÄÐÎʽÆô¶¯µ±Ç°sagaÁ÷£º

import { fork, takeEvery } from 'redux-saga/effects'
import { HomeSaga } from './Home/flux.js'
import { AppSaga } from './Appflux.js'

const sagas = [
...AppSaga,
...HomeSaga
]

export default function * root() {
yield sagas.map(saga => fork(saga))
}

ÈçÉÏ£¬Ê×ÏÈÊÕ¼¯ËùÓÐÄ£¿é¸ùsaga£¬È»ºó±éÀúÊý×飬Æô¶¯Ã¿Ò»¸ösagaÁ÷¸ùsaga¡£

sagaʵÀý

ÒÔAppSagaΪÀý£¬ÎÒÃÇÆÚÍûÔÚÓ¦ÓÃÆô¶¯Ê±¾Í·¢ÆðһЩÒì²½ÇëÇó£¬Èç»ñÈ¡ÎÄÕÂÁбíÊý¾Ý½«ÆäÌî³äÖÁredux store£¬¶ø²»µÈ´ýʹÓÃÊý¾ÝµÄ×é¼þäÖȾÍê²Å¿ªÊ¼ÇëÇóÊý¾Ý£¬Ìá¸ßÏìÓ¦ËÙ¶È£º

const REQUEST_POST_LIST = 'REQUEST_POST_LIST'
const RECEIVE_POST_LIST = 'RECEIVE_POST_LIST'

/**
* ÇëÇóÎÄÕÂÁбíActionCreator
* @param {object} payload
*/
function requestPostList (payload) {
return {
type: REQUEST_POST_LIST,
payload: payload
}
}

/**
* ½ÓÊÕÎÄÕÂÁбíActionCreator
* @param {*} payload
*/
function receivePostList (payload) {
return {
type: RECEIVE_POST_LIST,
payload: payload
}
}

/**
* ´¦ÀíÇëÇóÎÄÕÂÁбíSaga
* @param {*} payload ÇëÇó²ÎÊý¸ºÔØ
*/
function * getPostListSaga ({ payload }) {
const data = yield call(getPostList)
yield put(receivePostList(data))
}

// ¶¨ÒåAppSaga
export function * AppSaga (action) {
// ½ÓÊÕ×î½üÒ»´ÎÇëÇó£¬È»ºóµ÷ÓÃgetPostListSaga×ÓSaga
yield takeLatest(REQUEST_POST_LIST, getPostListSaga)
}

1. takeLatest£ºÔÚAppSagaÄÚʹÓÃtakeLatest·½·¨¼àÌýREQUEST_POST_LISTaction£¬Èô¶Ìʱ¼äÄÚÁ¬Ðø·¢Æð¶à´Îaction£¬Ôò»áÈ¡ÏûÇ°ÃæÎ´ÏìÓ¦µÄaction£¬Ö»·¢Æð×îºóÒ»´Îaction£»

2. getPostListSaga×ÓSaga£ºµ±½ÓÊÕµ½¸Ãactionʱ£¬µ÷ÓÃgetPostListSaga£¬²¢½«payload´«µÝ¸øËü£¬getPostListSagaÊÇAppSagaµÄ×Ó¼¶Saga£¬ÔÚÀïÃæ´¦Àí¾ßÌåÒì²½ÈÎÎñ£»

3. getPostList£ºgetPostListSaga»áµ÷ÓÃgetPostList·½·¨£¬·¢ÆðÒì²½ÇëÇó£¬Äõ½ÏìÓ¦Êý¾Ýºó£¬µ÷ÓÃreceivePostList ActionCreator£¬´´½¨²¢·Ö·¢action£¬È»ºóÓÉreducer´¦ÀíÏàÓ¦Âß¼­£»

getPostList·½·¨ÄÚÈÝÈçÏ£º

/**
* ÇëÇóÎÄÕÂÁÐ±í·½·¨
* @param {*} payload ÇëÇó²ÎÊý
* eg: {
* page: Num,
* per_page: Num
* }
*/
function getPostList (payload) {
return fetch({
...API.getPostList,
data: payload
}).then(res => {
if (res) {
let data = formatPostListData(res.data)
return {
total: parseInt(res.headers['X-WP-Total'.toLowerCase()], 10),
totalPages: parseInt(res.headers['X-WP-TotalPages'.toLowerCase()], 10),
...data
}
}
})
}

putÊÇredux-sagaÌṩµÄ¿É·Ö·¢action·½·¨£¬take£¬callµÈ¶¼ÊÇredux-sagaÌṩµÄAPI£¬¸ü¶àÄÚÈݲ鿴APIÎĵµ£¨https://redux-saga.js.org/docs/api/£©¡£

Ö®ºó±ã¿ÉÒÔÔÚÏîĿ·Óɸù×é¼þ×¢ÈëActionCreator£¬´´½¨action£¬È»ºósaga¾Í»á½ÓÊÕ½øÐд¦ÀíÁË¡£

sagaÓëReactotron

Ç°ÃæÒѾ­ÅäÖúÿÉÒÔʹÓÃReactotron²¶»ñÓ¦ÓÃËùÓÐreduxºÍaction£¬¶øredux-sagaÊÇÒ»ÀàreduxÖмä¼þ£¬ËùÒÔ²¶»ñsagasÐèÒª¶îÍâÅäÖ㬴´½¨storeʱ£¬ÔÚsagaÖмä¼þÄÚÌí¼ÓsagaMonitor·þÎñ£¬¼àÌýsaga:

const sagaMonitor = Config.useReactotron ? console.tron.createSagaMonitor() : null;
const sagaMiddleware = createSagaMiddleware({ sagaMonitor });
middleware.push(sagaMiddleware);

×ܽá

±¾ÎĽÏÏêϸµÄ×ܽáÁ˸öÈË´Ó0µ½1´î½¨Ò»¸öÏîÄ¿¼Ü¹¹µÄ¹ý³Ì£¬¶ÔReact£¬ ReduxÓ¦ÓúÍÏîÄ¿¹¤³Ìʵ¼ù¶¼ÓÐÁ˸üÉîµÄÀí½â¼°Ë¼¿¼£¬ÔÚ´óǰ¶Ë³É³¤Ö®Â·¼ÌÐøíÆíÂǰÐС£

   
5734 ´Îä¯ÀÀ       27
Ïà¹ØÎÄÕÂ

ÆóÒµ¼Ü¹¹¡¢TOGAFÓëArchiMate¸ÅÀÀ
¼Ü¹¹Ê¦Ö®Â·-ÈçºÎ×öºÃÒµÎñ½¨Ä££¿
´óÐÍÍøÕ¾µçÉÌÍøÕ¾¼Ü¹¹°¸ÀýºÍ¼¼Êõ¼Ü¹¹µÄʾÀý
ÍêÕûµÄArchimateÊÓµãÖ¸ÄÏ£¨°üÀ¨Ê¾Àý£©
Ïà¹ØÎĵµ

Êý¾ÝÖÐ̨¼¼Êõ¼Ü¹¹·½·¨ÂÛÓëʵ¼ù
ÊÊÓÃArchiMate¡¢EA ºÍ iSpace½øÐÐÆóÒµ¼Ü¹¹½¨Ä£
ZachmanÆóÒµ¼Ü¹¹¿ò¼Ü¼ò½é
ÆóÒµ¼Ü¹¹ÈÃSOAÂ䵨
Ïà¹Ø¿Î³Ì

ÔÆÆ½Ì¨Óë΢·þÎñ¼Ü¹¹Éè¼Æ
ÖÐ̨սÂÔ¡¢ÖÐ̨½¨ÉèÓëÊý×ÖÉÌÒµ
ÒÚ¼¶Óû§¸ß²¢·¢¡¢¸ß¿ÉÓÃϵͳ¼Ü¹¹
¸ß¿ÉÓ÷ֲ¼Ê½¼Ü¹¹Éè¼ÆÓëʵ¼ù