flux react_了解Flux,React.js架构
flux react 介绍 (Introduction)Welcome to the third installment of the Learning React series. Today we will be learning about how Facebook's Flux Architecture works, and how to use it in your own proj...
flux react
介绍 ( Introduction )
Welcome to the third installment of the Learning React series. Today we will be learning about how Facebook's Flux Architecture works, and how to use it in your own projects!
欢迎来到Learning React系列的第三部分。 今天,我们将学习Facebook的Flux Architecture如何工作,以及如何在您自己的项目中使用它!
If you haven't already, I strongly recommend you check out the first two installments in this series, Getting Started & Concepts and Building a Real Time Twitter Stream with Node and React. They aren't a hard prerequisite, but will certainly help you understand this article if you don't already have familiarity with React.js.
如果您还没有,我强烈建议您阅读本系列的前两部分, 入门和概念以及使用Node和React构建实时Twitter流 。 它们不是硬性前提,但如果您还不熟悉React.js,一定可以帮助您理解本文。
什么是助焊剂? ( What is Flux? )
Flux is an architecture that Facebook uses internally when working with React. It is not a framework or a library. It is simply a new kind of architecture that complements React and the concept of Unidirectional Data Flow.
Flux是Facebook在与React一起使用时内部使用的架构。 它不是框架或库。 它只是一种新型的体系结构,是对React和单向数据流概念的补充。
That said, Facebook does provide a repo that includes a Dispatcher library. The dispatcher is a sort of global pub/sub handler that broadcasts payloads to registered callbacks.
也就是说,Facebook确实提供了一个包含Dispatcher库的存储库。 调度程序是一种全局pub / sub处理程序,可将有效负载广播到已注册的回调中。
A typical Flux architecture will leverage this Dispatcher library, along with NodeJS's EventEmitter module in order to set up an event system that helps manage an applications state.
典型的Flux架构将利用此Dispatcher库以及NodeJS的EventEmitter模块,以建立有助于管理应用程序状态的事件系统。
Flux is probably better explained by explaining its individual components:
可以通过解释其各个组成部分来更好地解释助焊剂:
- Actions - Helper methods that facilitate passing data to the Dispatcher 动作-有助于将数据传递到分派器的助手方法
- Dispatcher - Receives actions and broadcasts payloads to registered callbacks 分派器-接收动作并将有效载荷广播到已注册的回调
- Stores - Containers for application state & logic that have callbacks registered to the dispatcher Stores-应用程序状态和逻辑的容器,这些容器的回调已注册到调度程序
- Controller Views - React Components that grab the state from Stores and pass it down via props to child components. 控制器视图-从组件获取状态并将其通过props传递给子组件的React组件。
Lets take a look at what this process looks like graphically:
让我们以图形方式查看此过程的外观:
How does the API relate to this?
API与这有何关系?
When you are working with data that is coming from (or going to) the outside, I've found that using Actions to introduce the data into the Flux Flow, and subsequently Stores, is the most painless way to go about it.
当您处理来自(或去往)外部的数据时,我发现使用动作将数据引入Flux Flow以及随后的Stores是最轻松的方法。
调度员 ( The Dispatcher )
So what's this Dispatcher all about?
那么,此Dispatcher的全部作用是什么?
The Dispatcher is basically the manager of this entire process. It is the central hub for your application. The dispatcher receives actions and dispatches the actions and data to registered callbacks.
调度程序基本上是整个过程的管理者。 它是您应用程序的中心。 调度程序接收操作,并将操作和数据调度到已注册的回调。
So it's essentially pub/sub?
所以它本质上是pub / sub?
Not exactly. The dispatcher broadcasts the payload to ALL of its registered callbacks, and includes functionality that allows you to invoke the callbacks in a specific order, even waiting for updates before proceeding. There is only ever one dispatcher, and it acts as the central hub within your application.
不完全是。 调度程序将有效负载广播到所有已注册的回调,并包括允许您以特定顺序调用回调的功能,甚至可以在继续之前等待更新。 永远只有一个调度程序,它是您应用程序中的中心枢纽。
Check out what one looks like below:
查看以下内容:
var Dispatcher = require('flux').Dispatcher;
var AppDispatcher = new Dispatcher();
AppDispatcher.handleViewAction = function(action) {
this.dispatch({
source: 'VIEW_ACTION',
action: action
});
}
module.exports = AppDispatcher;
In the above example, we create an instance of our Dispatcher and create a handleViewAction method. This abstraction is helpful if you are looking to distinguish between view triggered actions v.s. server/API triggered actions.
在上面的示例中,我们创建了Dispatcher的实例,并创建了handleViewAction方法。 如果要区分视图触发操作与服务器/ API触发操作之间的区别,则此抽象很有用。
Our method calls the dispatch method, which will broadcast the action
payload to all of its registered callbacks. This action can then be acted upon within Stores, and will result in a state update.
我们的方法调用了dispatch方法,该方法会将action
有效负载广播到其所有已注册的回调中。 然后可以在商店内执行此操作,并将导致状态更新。
The diagram below illustrates this process:
下图说明了此过程:
依存关系 (Dependencies)
One of the coolest parts of the provided Dispatcher module is the ability to define dependencies and marshall the callbacks on our Stores. So if one part of your application is dependent upon another part being updated first, in order to render properly, the Dispatcher's waitFor
method will be mighty useful.
所提供的Dispatcher模块中最酷的部分之一是能够定义依赖项并在我们的商店中编组回调。 因此,如果应用程序的一部分依赖于首先更新的另一部分,则为了正确呈现,Dispatcher的waitFor
方法将非常有用。
In order to utilize this feature, we need to store the return value of the Dispatcher's registration method on our Store as dispatcherIndex
, as shown below:
为了利用此功能,我们需要将Dispatcher的注册方法的返回值存储在Store中,作为dispatcherIndex
,如下所示:
ShoeStore.dispatcherIndex = AppDispatcher.register(function(payload) {
});
Then in our Store, when handling a dispatched action, we can use the Dispatcher's waitFor
method to ensure our ShoeStore has been updated:
然后在我们的商店中,当处理一个调度的动作时,我们可以使用Dispatcher的waitFor
方法来确保我们的ShoeStore已更新:
case 'BUY_SHOES':
AppDispatcher.waitFor([
ShoeStore.dispatcherIndex
], function() {
CheckoutStore.purchaseShoes(ShoeStore.getSelectedShoes());
});
break;
专卖店 ( Stores )
In Flux, Stores manage application state for a particular domain within your application. From a high level, this basically means that per app section, stores manage the data, data retrieval methods and dispatcher callbacks.
在Flux中,商店管理应用程序中特定域的应用程序状态。 从高层次上讲,这基本上意味着每个应用程序部分都由商店来管理数据,数据检索方法和调度程序回调。
Lets take a look at a basic Store:
让我们看一下基本商店:
var AppDispatcher = require('../dispatcher/AppDispatcher');
var ShoeConstants = require('../constants/ShoeConstants');
var EventEmitter = require('events').EventEmitter;
var merge = require('react/lib/merge');
// Internal object of shoes
var _shoes = {};
// Method to load shoes from action data
function loadShoes(data) {
_shoes = data.shoes;
}
// Merge our store with Node's Event Emitter
var ShoeStore = merge(EventEmitter.prototype, {
// Returns all shoes
getShoes: function() {
return _shoes;
},
emitChange: function() {
this.emit('change');
},
addChangeListener: function(callback) {
this.on('change', callback);
},
removeChangeListener: function(callback) {
this.removeListener('change', callback);
}
});
// Register dispatcher callback
AppDispatcher.register(function(payload) {
var action = payload.action;
var text;
// Define what to do for certain actions
switch(action.actionType) {
case ShoeConstants.LOAD_SHOES:
// Call internal method based upon dispatched action
loadShoes(action.data);
break;
default:
return true;
}
// If action was acted upon, emit change event
ShoeStore.emitChange();
return true;
});
module.exports = ShoeStore;
The most important thing we did above is to extend our store with NodeJS's EventEmitter. This allows our stores to listen/broadcast events. This allows our Views/Components to update based upon those events. Because our Controller View listens to our Stores, leveraging this to emit change events will let our Controller View know that our application state has changed and its time to retrieve the state to keep things fresh.
我们在上面所做的最重要的事情是使用NodeJS的EventEmitter扩展了我们的商店。 这使我们的商店可以收听/广播事件。 这使我们的视图/组件能够基于这些事件进行更新。 由于我们的Controller View监听我们的商店,因此利用它发出更改事件将使我们的Controller View知道我们的应用程序状态已更改,并且需要时间来检索状态以保持最新状态。
We also registered a callback with our AppDispatcher
using its register
method. This means that our Store is now listening to AppDispatcher
broadcasts. Our switch statement determines whether, for a given broadcast, if there are any relevant actions to take. If a relevant action is taken, a change event is emitted, and views that are listening for this event update their states.
我们还使用AppDispatcher
的register
方法AppDispatcher
注册了一个回调。 这意味着我们的商店现在正在收听AppDispatcher
广播。 我们的switch语句确定对于给定广播,是否要采取任何相关措施。 如果采取了相关的措施,则会发出更改事件,并且正在侦听此事件的视图将更新其状态。
Our public method getShoes
is used by our Controller View to retrieve all of the shoes in our _shoes
object and use that data in our components state. While this is a simple example, complicated logic can be put here instead of our views and helps keep things tidy.
Controller视图使用我们的公共方法getShoes
来检索_shoes
对象中的所有鞋子,并在组件状态下使用该数据。 尽管这是一个简单的示例,但是可以在此处放置复杂的逻辑而不是我们的视图,并有助于保持整洁。
动作创作者和动作 ( Action Creators & Actions )
Action Creators are collections of methods that are called within views (or anywhere else for that matter) to send actions to the Dispatcher. Actions are the actual payloads that are delivered via the dispatcher.
动作创建者是方法的集合,这些方法在视图(或与此有关的其他任何地方)中调用以将动作发送到分派器。 动作是通过调度程序传递的实际有效负载。
The way Facebook uses them, action type constants are used to define what action should take place, and are sent along with action data. Inside of registered callbacks, these actions can now be handled according to their action type, and methods can be called with action data as the arguments.
Facebook使用它们的方式,动作类型常量用于定义应执行的动作,并与动作数据一起发送。 在已注册的回调中,现在可以根据动作类型来处理这些动作,并且可以使用动作数据作为参数来调用方法。
Lets check out a constants definition:
让我们检查一个常量定义:
var keyMirror = require('react/lib/keyMirror');
module.exports = keyMirror({
LOAD_SHOES: null
});
Above we use React's keyMirror
library to, yup you guessed it, mirror our keys so that our value matches our key definition. Just by looking at this file, we can tell that our app loads shoes. The use of constants helps keep things organized, and helps give a high level view of what the app actually does.
上面,我们使用React的keyMirror
库来镜像您的键,以便我们的值与我们的键定义相匹配。 只需查看此文件,我们就可以知道我们的应用加载了鞋子。 常量的使用有助于使事情井井有条,并有助于从总体上了解应用程序的实际功能。
Now lets take a look at the corresponding Action Creator definition:
现在,让我们看一下相应的Action Creator定义:
var AppDispatcher = require('../dispatcher/AppDispatcher');
var ShoeStoreConstants = require('../constants/ShoeStoreConstants');
var ShoeStoreActions = {
loadShoes: function(data) {
AppDispatcher.handleAction({
actionType: ShoeStoreConstants.LOAD_SHOES,
data: data
})
}
};
module.exports = ShoeStoreActions;
In our example above, we created a method on our ShoeStoreActions
object that calls our dispatcher with the data we provided. We can now import this actions file into our view or API, and call ShoeStoreActions.loadShoes(ourData)
to send our payload to the Dispatcher, which will broadcast it. Then the ShoeStore will "hear" that event and call a method thats loads up some shoes!
在上面的示例中,我们在ShoeStoreActions
对象上创建了一个方法,该方法使用提供的数据调用调度程序。 现在,我们可以将此操作文件导入到视图或API中,并调用ShoeStoreActions.loadShoes(ourData)
将有效负载发送到分派器,分派器将对其进行广播。 然后,ShoeStore将“听到”该事件并调用加载一些鞋子的方法!
控制器视图 ( Controller Views )
Controller views are really just React components that listen to change events and retrieve Application state from Stores. They then pass that data down to their child components via props.
控制器视图实际上只是React组件,用于侦听更改事件并从商店中检索应用程序状态。 然后,他们通过道具将该数据传递到其子组件。
Here is what this looks like:
看起来像这样:
/** @jsx React.DOM */
var React = require('react');
var ShoesStore = require('../stores/ShoeStore');
// Method to retrieve application state from store
function getAppState() {
return {
shoes: ShoeStore.getShoes()
};
}
// Create our component class
var ShoeStoreApp = React.createClass({
// Use getAppState method to set initial state
getInitialState: function() {
return getAppState();
},
// Listen for changes
componentDidMount: function() {
ShoeStore.addChangeListener(this._onChange);
},
// Unbind change listener
componentWillUnmount: function() {
ShoesStore.removeChangeListener(this._onChange);
},
render: function() {
return (
<ShoeStore shoes={this.state.shoes} />
);
},
// Update view state when change event is received
_onChange: function() {
this.setState(getAppState());
}
});
module.exports = ShoeStoreApp;
In the example above, we listen for change events using addChangeListener, and update our application state when the event is received.
在上面的示例中,我们使用addChangeListener监听更改事件,并在收到事件时更新我们的应用程序状态。
Our application state data is held in our Stores, so we use the public methods on the Stores to retrieve that data and then set our application state.
我们的应用程序状态数据保存在我们的商店中,因此我们使用商店中的公共方法来检索该数据,然后设置我们的应用程序状态。
放在一起 ( Putting It All Together )
Now that we have gone through each individual part of the Flux architecture, we should have a much better idea of how this architecture actually works. Remember our graphical representation of this process from before? Lets have a look at a bit more granular view of this, now that we understand the function of each part of the flow:
现在我们已经遍历了Flux架构的每个部分,我们应该对这个架构的实际工作有一个更好的了解。 还记得我们以前对此过程的图形表示吗? 现在,让我们看一下更细粒度的视图,现在我们了解了流程的每个部分的功能:
结语 ( Wrap Up )
After reading this article, I hope that if you didn't "get" Facebook's Flux Architecture before, that now you can say you do. It wasn't until building something with it that I understood how complimentary to React.js it actually is.
阅读本文后,我希望如果您以前没有“了解” Facebook的Flux Architecture,现在可以说您同意了。 直到用它构建了一些东西,我才知道它实际上对React.js有多么的补充。
After you use Flux the first time, writing React without Flux feels like DOM traversal without jQuery. You can absolutely do it, but it feels less elegant and structured.
第一次使用Flux之后,编写没有Flux的React就像没有jQuery的DOM遍历。 您可以完全做到这一点,但感觉却不那么优雅和结构化。
If you want to use the Flux architecture, but you don't want to use React, check out Delorean, a Flux framework that you can use with Ractive.js or Flight. Another library worth looking at is Fluxxor, which takes a different approach to Flux architecture and provides a tighter coupling of Flux's components into a central Flux instance.
如果要使用Flux架构,但又不想使用React,请查看Delorean ,它是可与Ractive.js或Flight一起使用的Flux框架。 另一个值得研究的库是Fluxxor ,它采用了不同的Flux架构方法,并将Flux的组件紧密耦合到中央Flux实例中。
Again, I believe that to truly understand Flux, you actually have to use it, so stay tuned for the 4th and final installment of Learning React where we will be building a shopping cart with React.js and Flux Architecture!
再次,我相信要真正理解Flux,您实际上必须使用它,所以请继续学习Learning React的第四期和最后一期,我们将使用React.js和Flux Architecture构建购物车!
翻译自: https://scotch.io/tutorials/getting-to-know-flux-the-react-js-architecture
flux react
更多推荐
所有评论(0)