Maison > interface Web > tutoriel HTML > Plongée en profondeur dans la pile technologique Redux

Plongée en profondeur dans la pile technologique Redux

高洛峰
Libérer: 2017-02-18 14:24:39
original
1479 Les gens l'ont consulté

Introduction à redux

Cet article suppose que tout le monde a des connaissances sur l'architecture de réaction et de flux, et a également utilisé ou compris redux, il ne commencera donc pas par le plus basique, mais directement redux résume. Si vous n'avez pas utilisé redux, il est préférable de lire ici d'abord

Pour comprendre redux, nous devons d'abord résumer certains des principes de conception de redux :

  • Données uniques source

Dans Redux, une seule arborescence d'objets est utilisée pour stocker l'état de l'ensemble de l'application, qui sont les données qui seront utilisées dans l'ensemble de l'application, appelée store (stockage ). En plus des données stockées, le magasin peut également stocker l'état de l'ensemble de l'application (y compris l'état du routeur, qui sera présenté plus tard). Ainsi, via le magasin, il devient possible de mettre en œuvre une fonction de sauvegarde instantanée (créer un instantané). ) de l'ensemble de l'application. De plus, cette conception offre également la possibilité d'un rendu côté serveur.

  • Le statut est en lecture seule

Ceci est conforme au concept de conception de flux. Nous ne pouvons pas modifier le statut du magasin dans. composants (en fait, Redux générera un magasin basé sur le réducteur), mais ne peut déclencher des actions que pour itérer l'état actuel via la répartition. Ici, nous ne modifions pas directement l'état de l'application, mais renvoyons un tout nouvel état.

  • Les modifications d'état sont composées de fonctions pures

Le prototype du réducteur dans Redux ressemblera à ce qui suit, vous pouvez le considérer comme C'est la formule état précédent action = nouvel état :

(previousState, action) => newState
Copier après la connexion

Chaque réducteur est une fonction pure, ce qui signifie qu'il n'a pas d'effets secondaires. L'avantage de cette conception n'est pas seulement d'utiliser le réducteur pour modifier le. state C'est simple et peut être testé purement. De plus, redux peut enregistrer chaque statut de retour pour générer facilement un voyage dans le temps et suivre les résultats de chaque changement provoqué par l'action.

Si nous utilisons redux dans React, nous avons besoin à la fois de React-Redux et de Redux.

Architecture Redux et analyse du code source

Cette partie parle principalement de ma propre compréhension. Elle peut être un peu abstraite ou pas complètement correcte, vous pouvez donc l'ignorer directement.

createStore

La méthode principale de Redux est createStore. Les fonctions principales de React sont toutes couvertes dans createStore et son magasin généré final lui-même prend en charge la transmission de trois paramètres : réducteur, initialState. , et Enhancer , Enhancer peut être utilisé comme fonction d'emballage améliorée, ce qui n'est pas très couramment utilisé par nous.

Cette fonction maintient un currentState en interne, et ce currentState peut être renvoyé via la fonction getState (intégrée). De plus, elle implémente en fait un mode de publication-abonnement et s'abonne aux événements via store.subscribe. Ce travail est effectué par React-Redux qui nous aide à le faire implicitement, c'est-à-dire déclencher tous les écouteurs et mettre à jour l'intégralité de l'arborescence d'état en cas de répartition. De plus, la fonction de répartition intégrée déclenche le réducteur après une série de vérifications, puis l'état est modifié, puis l'écouteur est appelé en séquence pour terminer la mise à jour de l'ensemble de l'arborescence d'état.

middleWare

Les amis qui ont utilisé redux ne sont en fait pas étrangers aux middlewares tels que redux-thunk. En fait, il est indispensable dans de nombreux cas. Redux a également un bon support pour middleWare. Je pense que ce concept est quelque peu similaire au mécanisme middleware de nodejs : l'action passe tour à tour par chaque middleWare puis est transmise au suivant. Chaque middleWare peut également effectuer d'autres opérations telles que l'interruption ou la modification de l'action jusqu'à ce que la fonction de traitement finale soit terminée. remis au réducteur.

La fonction applyMiddleware de redux est très raffinée :

export default function applyMiddleware(...middlewares) {
  return (createStore) => (reducer, preloadedState, enhancer) => {
    var store = createStore(reducer, preloadedState, enhancer)
    var dispatch = store.dispatch
    var chain = []

    var middlewareAPI = {
      getState: store.getState,
      dispatch: (action) => dispatch(action)
      //注意这里的dispatch并不是一开始的store.dispatch,实际上是变化了的
    }
    chain = middlewares.map(middleware => middleware(middlewareAPI))
    dispatch = compose(...chain)(store.dispatch)

    return {
      ...store,
      dispatch
    }
  }
}
Copier après la connexion

Le noyau est dispatch = compose(...chain)(store.dispatch). .Appel, où le code source de compose :

export default function compose(...funcs) {
  if (funcs.length === 0) {
    return arg => arg
  }

  if (funcs.length === 1) {
    return funcs[0]
  }

  const last = funcs[funcs.length - 1]
  const rest = funcs.slice(0, -1)
  return (...args) => rest.reduceRight((composed, f) => f(composed), last(...args))
}
Copier après la connexion

Appelle le résultat de l'exécution de la fonction précédente à la fonction suivante.

En fait, le processus d'écriture d'un middleware est très simple. Par exemple, redux-trunk se compose en fait de ceci :

function createThunkMiddleware(extraArgument) {
  return ({ dispatch, getState }) => next => action => {
    if (typeof action === 'function') {
      return action(dispatch, getState, extraArgument);
    }

    return next(action);
  };
}

const thunk = createThunkMiddleware();
thunk.withExtraArgument = createThunkMiddleware;

export default thunk;
Copier après la connexion

redux et routage

Bien sûr. , Nous déclarons d'abord que lereact-router de l'ensemble d'outilsreact ne doit pas nécessairement être utilisé avec redux, mais redux a un autrereact-router-redux qui peut être utilisé avecreact-router et redux, et l'effet est très bon .

Étant donné que nous n'expliquons pas comment utiliser React-Router dans cette partie, veuillez vous référer à la documentation chinoise pour l'utilisation de React-Router.

Les fonctionnalités de React-Router

  • permettent aux développeurs de déclarer des routes via des balises JSX, ce qui rend nos routes très conviviales à écrire et la capacité d'expression du routage déclaratif relativement fort.

  • Routes imbriquées et correspondance d'itinéraire : Vous pouvez transmettre des paramètres dans le chemin spécifié :

<Route path="/mail/:mailId" component={Mail} />
Copier après la connexion

De plus, si les paramètres sont facultatifs , nous pouvons le mettre entre parenthèses (:paramètre facultatif).

  • Prend en charge plusieurs méthodes de changement d'itinéraire : nous savons que les méthodes de changement d'itinéraire actuelles ne sont rien de plus que l'utilisation de hashchange et pushState. La première a une meilleure compatibilité avec les navigateurs, mais ce n'est pas la même chose. URL, alors que cette dernière nous offre une expérience URL élégante, mais elle nécessite que le serveur résolve le problème de l'actualisation de n'importe quel chemin (le serveur doit automatiquement rediriger vers la page d'accueil).

为什么需要react-router-redux

简单的说,react-router-redux让我们可以把路由也当作状态的一部分,并且可以使用redux的方式改变路由:直接调用dispatch:this.props.push(“/detail/”);,这样把路由也当作一个全局状态,路由状态也是应用状态的一部分,这样可能更有利于前端状态管理。

react-router-redux是需要配合react-router来使用的,并不能单独使用,在原本的项目中添加上react-router-redux也不复杂:

import { createStore, combineReducers, compose, applyMiddleware } from 'redux';
import { routerReducer, routerMiddleware } from 'react-router-redux';
import { hashHistory } from 'react-router';

import ThunkMiddleware from 'redux-thunk';
import rootReducer from './reducers';
import DevTools from './DevTools';

const finalCreateStore = compose(
  applyMiddleware(ThunkMiddleware,routerMiddleware(hashHistory)),
  DevTools.instrument()
)(createStore);

console.log("rootReducer",rootReducer);

const reducer = combineReducers({
  rootReducer,
  routing: routerReducer,
});

export default function configureStore(initialState) {
  const store = finalCreateStore(reducer, initialState);
  return store;
}
Copier après la connexion

另外,上文提到的demoreact-router-redux-demo用了react-router和react-router-redux,当然也用到了redux的一些别的比较好的工作,比如redux-devtools,有兴趣的朋友可以点击这里

redux 与组件

这一部分讲述的是一种组件书写规范,并不是一些库或者架构,这些规范有利于我们在复杂的项目中组织页面,不至于混乱。

从布局的角度看,redux强调了三种不同的布局组件,Layouts,Views,Components:

  • Layouts: 指的是页面布局组件,描述了页面的基本结构,可以是无状态函数,一般就直接设置在最外层router的component参数中,并不承担和redux直接交互的功能。比如我项目中的Layouts组件:

const Frame = (props) =>
       <p className="frame">
           <p className="header">
               <Nav />
           </p>
           <p className="container">
               {props.children}
           </p>
       </p>;
Copier après la connexion
  • Views组件,我认为这个组件是Components的高阶组件或者Components group,这一层是可以和redux进行交互并且处理数据的,我们可以将一个整体性功能的组件组放在一个Views下面(注:由于我给出的demo十分简单,因此Views层和Components层分的不是那么开)

  • Components组件,这是末级渲染组件,一般来说,这一层级的组件的数据通过props传入,不直接和redux单向数据流产生交互,可以是木偶般的无状态组件,或者是包含自身少量交互和状态的组件,这一层级的组件可以被大量复用。

总而言之,遵守这套规范并不是强制性的,但是项目一旦稍微复杂一些,这样做的好处就可以充分彰显出来。

redux 与表单

redux的单向数据流相对于双向数据绑定,在处理表单等问题上的确有点力不从心,但是幸运的是已经开源了有几个比较不错的插件:

  • redux-form-utils,好吧,这个插件的star数目非常少,但是他比较简单,源代码也比较短,只有200多行,所以这是一个值得我们看源码学习的插件(它的源码结构也非常简单,就是先定一个一个高阶组件,这个高阶组件可以给我们自己定义的表单组件传入新的props,定制组件,后一部分就是定义了一些action和reducer,负责在内容变化的时候通知改变状态树),但是缺憾就是这个插件没有对表单验证做工作,所以如果我们需要表单验证,还是需要自己做一些工作的。

    • 另外还有一地方,这个插件源代码写法中用到了::这种ES6的语法,这其实是一种在es6中class内部,使用babel-preset-stage-0即可使用的语法糖:::this.[functionName] 等价于 this.[functionName].bind(this, args?)  

  • redux-form,这个插件功能复杂,代码完善,体量也非常庞大,可以参考文档进行使用,但是读懂源代码就是比较麻烦的事情了。不过这个插件需要在redux的应用的state下挂载一个节点,这个节点是不需要开发者自己来操控的,他唯一需要做的事情就是写一个submit函数即可。我在自己的demo中也把一个例子稍加改动搬了过来,感觉用起来比较舒服。

redux 性能优化

想要做到redux性能优化,我们首先就要知道redux的性能可能会在哪些地方受到影响,否则没有目标是没有办法性能优化的。

因为我也不是使用redux的老手,所以也并不能覆盖所有性能优化的点,我总结两点:

  • 有的时候,我们需要的数据格式会自带冗余,可以抽取出一些公共的部分从而缩减大小,比如我们需要的数据格式可能是这样的:

[
    {
        name:"Nike",
        title:"国家一级运动员","国家一级裁判员"
    }
    {
        name:"Jenny",
        title:"国家一级裁判员"
    }
    {
        name:"Mark",
        title:"国家一级运动员"
    }
]
Copier après la connexion

这个时候实际上我们可以优化成这样:

[
    {
    "国家一级运动员":"Nike","Mark"
    "国家一级裁判员":"Jenny","Nike"
    }
]
Copier après la connexion

这个时候,我们可以直接把后者当作store的格式,而我们用reselect这个库再转变成我们所要的格式,关于reselect怎么用上述链接有更详细的例子,在这里我就不过多介绍了。

  • 事实上,对于redux来说,每当store发生改变的时候,所有的connect都会重新计算,在一个大型应用中,浪费的时间可想而知,为了减少性能浪费,我们可以对connect中的selector做缓存。

La bibliothèque de resélection mentionnée ci-dessus a sa propre fonctionnalité de mise en cache. Nous pouvons déterminer s'il convient d'utiliser la mise en cache en comparant les paramètres. La fonctionnalité de fonction pure est utilisée ici.

La fonction de mise en cache de reselect peut être personnalisée par l'utilisateur


Pour des articles plus approfondis sur la pile technologique Redux, veuillez faire attention au site Web chinois PHP !

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal