Maison >interface Web >Questions et réponses frontales >Que signifie flux en réaction ?
In React, Flux est une solution de gestion de l'état public, utilisée pour construire l'architecture d'application des applications Web côté client et gérer l'état public sous la forme d'un flux de données unidirectionnel.
L'environnement d'exploitation de ce tutoriel : système Windows 7, React version 17.0.1, ordinateur Dell G3.
Qu'est-ce que flux
flux est une solution de gestion d'état publique similaire à vuex in React. Il s'agit de l'architecture d'application officiellement donnée par Facebook pour créer des applications Web clientes, en utilisant le flux de données unidirectionnel Gérer. statut public sous la forme de
. Cela ressemble plus à un modèle qu'à un cadre formel. Les développeurs peuvent rapidement démarrer avec Flux sans avoir besoin de trop de nouveau code.cnpm i flux -S
的方式进行安装。
flux的组成
View:视图层
Action:视图发出的消息
Dispatcher:派发者,用来接收Action,执行回调函数
Store:数据层,存放状态,一旦发生改动,
flux的工作流程
Flux 的最大特点,就是数据的"单向流动"。
用户访问 View
View 发出用户的 Action
Dispatcher 收到 Action,要求 Store 进行相应的更新
Store 更新后,发出一个"change"事件
View 收到"change"事件后,更新页面
上面过程中,数据总是"单向流动",任何相邻的部分都不会发生数据的"双向流动"。这保证了流程的清晰。
读到这里,你可能感到一头雾水,OK,这是正常的。接下来,我会详细讲解每一步。
请打开 Demo 的首页index.jsx
,你会看到只加载了一个组件。
// index.jsx var React = require('react'); var ReactDOM = require('react-dom'); var MyButtonController = require('./components/MyButtonController'); ReactDOM.render( <MyButtonController/>, document.querySelector('#example') );
上面代码中,你可能注意到了,组件的名字不是 MyButton
,而是 MyButtonController
。这是为什么?
这里,我采用的是 React 的 controller view 模式。"controller view"组件只用来保存状态,然后将其转发给子组件。MyButtonController
的源码很简单。
// components/MyButtonController.jsx var React = require('react'); var ButtonActions = require('../actions/ButtonActions'); var MyButton = require('./MyButton'); var MyButtonController = React.createClass({ createNewItem: function (event) { ButtonActions.addNewItem('new item'); }, render: function() { return <MyButton onClick={this.createNewItem} />; } }); module.exports = MyButtonController;
上面代码中,MyButtonController
将参数传给子组件MyButton
。后者的源码甚至更简单。
// components/MyButton.jsx var React = require('react'); var MyButton = function(props) { return <div> <button onClick={props.onClick}>New Item</button> </div>; }; module.exports = MyButton;
上面代码中,你可以看到MyButton
是一个纯组件(即不含有任何状态),从而方便了测试和复用。这就是"controll view"模式的最大优点。
MyButton
只有一个逻辑,就是一旦用户点击,就调用this.createNewItem
方法,向Dispatcher发出一个Action。
// components/MyButtonController.jsx // ... createNewItem: function (event) { ButtonActions.addNewItem('new item'); }
上面代码中,调用createNewItem
方法,会触发名为addNewItem
的Action。
每个Action都是一个对象,包含一个actionType
属性(说明动作的类型)和一些其他属性(用来传递数据)。
在这个Demo里面,ButtonActions
对象用于存放所有的Action。
// actions/ButtonActions.js var AppDispatcher = require('../dispatcher/AppDispatcher'); var ButtonActions = { addNewItem: function (text) { AppDispatcher.dispatch({ actionType: 'ADD_NEW_ITEM', text: text }); }, };
上面代码中,ButtonActions.addNewItem
方法使用AppDispatcher
,把动作ADD_NEW_ITEM
派发到Store。
Dispatcher 的作用是将 Action 派发到 Store、。你可以把它看作一个路由器,负责在 View 和 Store 之间,建立 Action 的正确传递路线。注意,Dispatcher 只能有一个,而且是全局的。
Facebook官方的 Dispatcher 实现输出一个类,你要写一个AppDispatcher.js
,生成 Dispatcher 实例。
// dispatcher/AppDispatcher.js var Dispatcher = require('flux').Dispatcher; module.exports = new Dispatcher();
AppDispatcher.register()
方法用来登记各种Action的回调函数。
// dispatcher/AppDispatcher.js var ListStore = require('../stores/ListStore'); AppDispatcher.register(function (action) { switch(action.actionType) { case 'ADD_NEW_ITEM': ListStore.addNewItemHandler(action.text); ListStore.emitChange(); break; default: // no op } })
上面代码中,Dispatcher收到ADD_NEW_ITEM
动作,就会执行回调函数,对ListStore
进行操作。
记住,Dispatcher 只用来派发 Action,不应该有其他逻辑。
Store 保存整个应用的状态。它的角色有点像 MVC 架构之中的Model 。
在我们的 Demo 中,有一个ListStore
,所有数据都存放在那里。
// stores/ListStore.js var ListStore = { items: [], getAll: function() { return this.items; }, addNewItemHandler: function (text) { this.items.push(text); }, emitChange: function () { this.emit('change'); } }; module.exports = ListStore;
上面代码中,ListStore.items
用来保存条目,ListStore.getAll()
用来读取所有条目,ListStore.emitChange()
Utilisez cnpm i flux -S
pour installer.
index.jsx
et vous verrez qu'un seul composant est chargé. 🎜// stores/ListStore.js var EventEmitter = require('events').EventEmitter; var assign = require('object-assign'); var ListStore = assign({}, EventEmitter.prototype, { items: [], getAll: function () { return this.items; }, addNewItemHandler: function (text) { this.items.push(text); }, emitChange: function () { this.emit('change'); }, addChangeListener: function(callback) { this.on('change', callback); }, removeChangeListener: function(callback) { this.removeListener('change', callback); } });🎜Dans le code ci-dessus, vous avez peut-être remarqué que le nom du composant n'est pas
MyButton
, mais MyButtonController
. pourquoi donc? 🎜🎜Ici, j'utilise le mode d'affichage du contrôleur de React. Le composant « vue du contrôleur » est uniquement utilisé pour enregistrer l'état, puis le transmettre aux composants enfants. Le code source de MyButtonController
est très simple. 🎜// components/MyButtonController.jsx var React = require('react'); var ListStore = require('../stores/ListStore'); var ButtonActions = require('../actions/ButtonActions'); var MyButton = require('./MyButton'); var MyButtonController = React.createClass({ getInitialState: function () { return { items: ListStore.getAll() }; }, componentDidMount: function() { ListStore.addChangeListener(this._onChange); }, componentWillUnmount: function() { ListStore.removeChangeListener(this._onChange); }, _onChange: function () { this.setState({ items: ListStore.getAll() }); }, createNewItem: function (event) { ButtonActions.addNewItem('new item'); }, render: function() { return <MyButton items={this.state.items} onClick={this.createNewItem} />; } });🎜Dans le code ci-dessus,
MyButtonController
transmet les paramètres au sous-composant MyButton
. Le code source de ce dernier est encore plus simple. 🎜// components/MyButton.jsx var React = require('react'); var MyButton = function(props) { var items = props.items; var itemHtml = items.map(function (listItem, i) { return <li key={i}>{listItem}</li>; }); return <div> <ul>{itemHtml}</ul> <button onClick={props.onClick}>New Item</button> </div>; }; module.exports = MyButton;🎜Dans le code ci-dessus, vous pouvez voir que
MyButton
est un composant pur (c'est-à-dire qu'il ne contient aucun état), ce qui facilite les tests et la réutilisation. C'est le plus gros avantage du mode "control view". 🎜🎜MyButton
n'a qu'une seule logique, qui consiste à appeler la méthode this.createNewItem
une fois que l'utilisateur clique dessus et à envoyer une action au répartiteur. 🎜rrreee🎜Dans le code ci-dessus, l'appel de la méthode createNewItem
déclenchera une action nommée addNewItem
. 🎜actionType
(décrivant le type d'action) et quelques autres attributs (utilisés pour transmettre des données). 🎜🎜Dans cette démo, l'objet ButtonActions
est utilisé pour stocker toutes les actions. 🎜rrreee🎜Dans le code ci-dessus, la méthode ButtonActions.addNewItem
utilise AppDispatcher
pour envoyer l'action ADD_NEW_ITEM
au Store. 🎜AppDispatcher.js
pour générer une instance de Dispatcher. La méthode 🎜rrreee🎜AppDispatcher.register()
est utilisée pour enregistrer diverses fonctions de rappel d'action. 🎜rrreee🎜Dans le code ci-dessus, lorsque Dispatcher reçoit l'action ADD_NEW_ITEM
, il exécutera la fonction de rappel et exploitera ListStore
. 🎜🎜N'oubliez pas que Dispatcher n'est utilisé que pour distribuer des actions et ne devrait pas avoir d'autre logique. 🎜ListStore
où toutes les données sont stockées. 🎜rrreee🎜Dans le code ci-dessus, ListStore.items
est utilisé pour enregistrer les éléments, ListStore.getAll()
est utilisé pour lire tous les éléments, ListStore.emitChange( ) est utilisé pour émettre un événement "change". 🎜🎜Étant donné que le Store doit envoyer l'événement "change" à la View après le changement, il doit implémenter l'interface d'événement. 🎜<pre class="brush:js;toolbar:false;">// stores/ListStore.js
var EventEmitter = require(&#39;events&#39;).EventEmitter;
var assign = require(&#39;object-assign&#39;);
var ListStore = assign({}, EventEmitter.prototype, {
items: [],
getAll: function () {
return this.items;
},
addNewItemHandler: function (text) {
this.items.push(text);
},
emitChange: function () {
this.emit(&#39;change&#39;);
},
addChangeListener: function(callback) {
this.on(&#39;change&#39;, callback);
},
removeChangeListener: function(callback) {
this.removeListener(&#39;change&#39;, callback);
}
});</pre><p>上面代码中,<code>ListStore
继承了EventEmitter.prototype
,因此就能使用ListStore.on()
和ListStore.emit()
,来监听和触发事件了。
Store 更新后(this.addNewItemHandler()
)发出事件(this.emitChange()
),表明状态已经改变。 View 监听到这个事件,就可以查询新的状态,更新页面了。
现在,我们再回过头来修改 View ,让它监听 Store 的 change
事件。
// components/MyButtonController.jsx var React = require('react'); var ListStore = require('../stores/ListStore'); var ButtonActions = require('../actions/ButtonActions'); var MyButton = require('./MyButton'); var MyButtonController = React.createClass({ getInitialState: function () { return { items: ListStore.getAll() }; }, componentDidMount: function() { ListStore.addChangeListener(this._onChange); }, componentWillUnmount: function() { ListStore.removeChangeListener(this._onChange); }, _onChange: function () { this.setState({ items: ListStore.getAll() }); }, createNewItem: function (event) { ButtonActions.addNewItem('new item'); }, render: function() { return <MyButton items={this.state.items} onClick={this.createNewItem} />; } });
上面代码中,你可以看到当MyButtonController
发现 Store 发出 change
事件,就会调用 this._onChange
更新组件状态,从而触发重新渲染。
// components/MyButton.jsx var React = require('react'); var MyButton = function(props) { var items = props.items; var itemHtml = items.map(function (listItem, i) { return <li key={i}>{listItem}</li>; }); return <div> <ul>{itemHtml}</ul> <button onClick={props.onClick}>New Item</button> </div>; }; module.exports = MyButton;
推荐学习:《react视频教程》
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!