如何在使用 Flux 时使 ReactJS 更好地发挥作用.docx
- 文档编号:3816442
- 上传时间:2022-11-25
- 格式:DOCX
- 页数:15
- 大小:120.63KB
如何在使用 Flux 时使 ReactJS 更好地发挥作用.docx
《如何在使用 Flux 时使 ReactJS 更好地发挥作用.docx》由会员分享,可在线阅读,更多相关《如何在使用 Flux 时使 ReactJS 更好地发挥作用.docx(15页珍藏版)》请在冰豆网上搜索。
如何在使用Flux时使ReactJS更好地发挥作用
如何在使用Flux时使ReactJS更好地发挥作用
我很想知道为什么当React自身很好的情况下我们还需要Flux(whydoweneedFluxwhenReactisfineonitsown)。
我在ReactJS方面没有太多的开发经验,这就是为什么我无法意识到Flux的作用。
基于对学习的渴望,我告诉自己振作一点,学习Flux的同时也帮助培训他人。
作者:
oschina来源:
开源中国|2016-10-2113:
08
收藏
分享
我最近开始学习ReactJS。
有了GitHub上面这个很棒的文档让我觉得它很容易学习。
我用ReactJS创建了一个示例应用,而且它工作得很好!
有了一些经验之后,我想先提一下它的两个要点:
HTML和Javascript在一个文件时会变得容易维护。
在组件驱动开发中,DOM拆分成组件可以使其可重用以及易测试。
然后我听说了ReactwithFlux,我很想知道为什么当React自身很好的情况下我们还需要Flux(whydoweneedFluxwhenReactisfineonitsown)。
我在ReactJS方面没有太多的开发经验,这就是为什么我无法意识到Flux的作用。
基于对学习的渴望,我告诉自己振作一点,学习Flux的同时也帮助培训他人。
用ReactJS创建一个应用,但最初并没有使用Flux,这样便于理解它的优势,比如:
1.可维护性
2.可读性
3.单向数据流
为了在实践中有一样的效果,我们来看看使用Flux和不使用Flux来创建应用程的区别。
让我们从了解Flux的基本定义/架构开始。
Flux框架
Flux有以下四个要点
1.Action(操作):
Actions非常简单,因为它们只需要从View接收请求并将其传递给Dispatcher。
它充当的是View和Dispatcher之间的中介。
2.Dispatcher(调度):
Dispatcher负责将信息传递给Store。
它通过Dispatcher中的
3.Store(存储):
Stores与数据一起工作。
它根据每个来自View的请求与后端服务器通信。
4.View(视图):
Views负责显示信息。
如果视图需要信息就会从Store中获取,如果需要执行某些操作或者更新、添加某些信息则会告知Action。
Action调用Dispatcher,Dispatcher反过来从Store获取数据。
假设要创建一个TODO应用。
这是一个单页应用,分为以下几个组件:
∙Header
∙TodoCount
∙TodoForm
∙TodoList
∙TodoItem
在浏览器中,组件将如下图所示:
预期的特性
∙TodoCount显示所有TodoItem的数量。
∙TodoForm有一个输入框。
∙提交表单时,新的TodoItem会添加到TodoList,TodoCount也会相应地增加。
不使用Flux的应用
创建TodoItem类用于渲染单个的todoitem。
它将从父组件接收todoitem的信息:
1.var TodoItem = React.createClass({
2.render:
function() {
3.return (
4.
5.}
6.})
下面的组件是TodoList,它负责渲染所有的todoitems。
这个组件通过props从父类获取“数据”。
“this.props.data”是我们之前创建的用于迭代和调用TodoItem的一个列表。
1.var TodoList = React.createClass({
2. render:
function() {
3. var TodoTasks = this.props.data.map(function(todoItem) {
4. return (
5. < TodoItem user = { todoItem.user } task = {todoItem.task} key = { todoItem.id } />
6. )
7. })
8. return (
9. < div className = "todo list" >
10.
- Todo List
11. {TodoTasks}
12.
13.
14. )
15. }
16.});
TodoCount组件负责显示items的计数。
它从TodoHeader组件获取计数。
1.var TodoCount = React.createClass({
2. render:
function() {
3. return (
4.
5. }
6.});
TodoHeader组件显示应用程序的头,它调用TodoCount组件显示所有items的计数。
1.var TodoHeader = React.createClass({
2. render:
function() {
3. return (
4.
5. Header
6. < TodoCount count = { this.props.count}
7. />
8.
9. )
10. }
11.})
下面是TodoForm组件。
我们同样关注它是因为除了渲染之外它还要创建数据。
handleSubmit方法在单击提交按钮时调用,它调用从Application组件获取的TodoSubmit方法。
我当时有一些疑问:
∙为什么要用这个方法?
∙为什么Application组件提交表单而不是TodoForm?
原因是Application组件是所有组件的父/祖父组件。
并且数据流是从父组件到子组件的并且子组件不能改变父组件的状态。
此外,同级组件之间不能有任何通信数据流。
现在如果TodoForm要提交表单,那么这些信息要如何传递到TodoList或TodoHeader组件?
这就是为什么要让Application组件负责提交表单。
1.var TodoForm = React.createClass({
2. getInitialState:
function() {
3. console.log("inside todo form of initial")
4. return { user:
'', task:
'' }
5. },
6. handleUserChange:
function(e) {
7. this.setState({ user:
e.target.value })
8. },
9. handleTaskChange:
function(e) {
10. this.setState({ task:
e.target.value })
11. },
12. handleSubmit:
function(e) {
13. e.preventDefault();
14. this.props.onTodoSubmit({ user:
this.state.user, task:
this.state.task })
15. this.setState({ user:
'', task:
'' })
16. },
17. render:
function() {
18. return (
19.
27. )
28. }
29.})
应用组件是所有组件的父组件。
于是它涉及的方法需要讨论一下。
loadDataFromServer–它会从服务器加载数据,但在例子中没有任何服务器,所以就将数据硬编码了。
handleTodoSubmit–这个方法将由TodoForm调用,就像TodoForm组件中讲解的那要。
。
当这个方法被调用时,它将随着新创建的Todoitem改变状态,这个新的Todoitem会触发Application组件的重新渲染,并且所有子组件将随着新的信息而更新。
1.var TODO = React.createClass({
2. getInitialState:
function() {
3. return { data:
[] }
4. },
5. loadDataFromServer:
function() {
6. this.setState({
7. data:
[
8. { id:
1, user:
"Adam", task:
"This is task1"},
9. { id:
2, user:
"Ricky",task:
"This is task2"}
10. ]
11. })
12. },
13. componentDidMount:
function() {
14. this.loadDataFromServer()
15. },
16. handleTodoSubmit:
function(todo) {
17. todo.id = Date.now()
18. var todos = this.state.data
19. var newTodos = todos.concat([todo])
20. this.setState({
21. data:
newTodos
22. })
23. },
24. render:
function() {
25. return (
26.
27.
28.
29. < TodoList data = { this.state.data } />
30.
31. )
32. }
33.})
34.ReactDOM.render( < TODO /> , document.getElementById("example"))
可以看到,如果同级组件想要彼此通信,就需要将数据传递到它们的父组件。
像是例子中的TodoForm想告知TodoList有新的item被添加了。
这就是为什么Application组件传递回调方法handleTodoSubmit。
所以在TodoForm提交时它通过回调调用Application组件的handleTodoSubmit方法。
而handleTodoSubmit正在更新Application的状态,这使得通过更新TodoItem和TodoHeader来重新渲染Application组件。
在例子中,只有1个层级,但在实时情况下,可能有多个层级,而最内层的子层想要更新其他层的最内层子层。
这就需要传递的回调方法覆盖所有层级。
但这会使其不易维护,也大大降低可读性,这也使React的优势大打折扣。
现在试试相同的应用使用Flux
正如我们所看到的,Flux有4层。
根据它的这个结构编写一个代码。
Action
Actions被Views调用。
如果View要在Store中更新数据,则View会告知Action这个变更。
这里创建了AppAction。
在这里,只有一个action,即addItem。
当要添加一个新的todoItem时,这将会被调用。
这个action进一步调用dispatcher(AppDispatcher)的handleViewAction。
1.var AppDispatcher = require('../dispatchers/app-dispatcher');
2.var AppAction = {
3. addItem:
function(item) {
4. AppDispatcher.handleViewAction({
5. actionType:
'ADD_ITEM',
6. item:
item
7. })
8. }
9.}
Dispatcher
在AppDispatcher中,定义了由AppLIcation调用的handleViewAction。
在handleViewAction中,action会被传递用做告知执行什么action。
handleViewAction里面有一个this.dispatch,这是一个Dispatcher的预定义方法。
这个方法会在内部调用Store。
1.var Dispatcher = require("flux").Dispatcher;
2.var assign = Object.assign;
3.var AppDispatcher = assign(new Dispatcher(), {
4.handleViewAction:
function(action) {
5.console.log('action', action)
6.this.dispatch({
7.source:
'VIEW_ACTION',
8.action:
action
9.})
10.}
11.});
Store(存储)
接下来我们一个个地讨论Store的方法。
dispatcherIndex–由于AppDispatcher.register,执行从这里开始。
每当调用Dispatcher的dispatch方法时,它会在所有定义AppDispatcher.register的地方传递action的信息。
在例子中,只有一个action——“ADD_ITEM”,但在大多数情况下,将有多个action。
因此,需要首先定义action的类型,基于此,还会执行actions并调用emit方法。
这里,在dispatcherIndex方法中调用addTodoItem方法,之后是调用emitChange。
addTodoItem–在这个方法中,除了将新的todoitem添加到到todoItems数组不会做其它事情。
emitChange–在emitChange中,使用this.emit(CHANGE_EVENT)方法可以允许CHANGE_EVENT的监听者知道某些东西发生了变化。
addListener–Views用这个方法来监听CHANGE_EVENT。
removeListener–Views用这个方法来移除监听器。
getTodoItems–这个方法会返回所有的todos。
它会被TodoList组件调用。
getTodoCount–这个方法会返回所有todos的计数。
它会被TodoCount组件调用。
component.
1.var AppDispatcher = require('../dispatchers/app-dispatcher');
2.var assign = Object.assign;
3.var EventEmitter = require('events').EventEmitter;
4.var CHANGE_EVENT = 'change';
5.var todoItems = [
6. { id:
1, user:
"Adam", task:
"This is task1"},
7. { id:
2, user:
"Ricky", task:
"This is task2"}
8.];
9.var AppStore = assign(EventEmitter.prototype, {
10. emitChange:
function() {
11. this.emit(CHANGE_EVENT)
12. },
13. addListener:
function(callback) {
14. this.on(CHANGE_EVENT, callback)
15. },
16. removeChangeListener:
function(callback) {
17. this.removeListener(CHANGE_EVENT, callback)
18. },
19. dispatcherIndex:
AppDispatcher.register(function(payload) {
20. var action = payload.action;
21. if (action.actionType == "ADD_ITEM") {
22. this.addTodoItem(payload.action.item);
23. }
24. AppStore.emitChange();
25. return true;
26. }),
27. getTodoItems:
function() {
28. return todoItems;
29. },
30. getTodoCount:
function() {
31. return todoItems.length;
32. },
33. addTodoItem:
function(todo) {
34. todoItems.push(todo);
35. }
36.})
View(视图)/Components(组件)
在TodoTask中,与上面的例子一样没有改变任何东西。
1.var TodoTask = React.createClass({
2. render:
function() {
3. return (
4.
5. )
6. }
7.})
在TodoList组件中,通过在getInitialState中调用AppStore.getTodoItems直接从Store提取todoitems。
现在的问题是,“这个组件怎样才能知道新的todoitem是什么时候添加的?
”
答案就在componentWillMount中。
在这个方法中,调用AppStore.addChangeListener,它监听在Store的addChangeListener中定义的事件。
如果有任何更改,那么它将调用_onChange来重置状态。
1.var TodoList = React.createClass({
2. getInitialState:
function() {
3. return { todoItems:
AppStore.getTodoItems() }
4. },
5. componentWillMount:
function() {
6. AppStore.addChange
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 如何在使用 Flux 时使 ReactJS 更好地发挥作用 如何 使用 更好 发挥作用