使用 React 和 Flux 创建一个记事本应用

React,来自 Facebook,是一个用来创建用户界面的非常优秀的类库。唯一的问题是 React 不会关注于你的应用如何处理数据。大多数人把 React 当做 MV* 中的 V。所以,Facebook 引入了一种称作 Flux 的模式,提供了一个功能上的通道,可用于应用内的数据处理。这个教程简短的介绍了 Flux 模式并且展示了如何使用 React 和 Flux 架构搭建一个记事本应用。

Flux 入门

Flux 依赖于一个单的数据流。在这个 Flux 模式中有两个关键的组件:

  1. Stores :一个 store 组件,恰如其名,存储这应用的数据。
  2. Actions :新的数据通过 actions 流入 stores。当 actions 被调用时, Stores 监听 actions 并且会做一些反馈(比如修改数据)。这保证了数据的单向性。

为了增强这个概念,我们做一个实实在在的例子。比如,在一个记事本应用中你可能会有下面的安排:

  1. 一个叫做 NoteStore 的 store 用来存储日记列表。
  2. 要有一个叫做 createNote 的 action。NoteStore 监听到 createNode 的 action 然后当 action 被调用的时候用一个新的日记来更新列表。数据仅仅能通过 action 流入到 store 中。
  3. 每 次数据发生变化时 NoteStore 触发一个事件。你的 React 组件,假如叫做 NodeListComponent,监听这个事件然后更新存在于 view 层中日记的列表。这就是从 store 流出的数据的流动方式。所以,数据流可以形象化的看做下面这样:

Flux 模式最大的优势就是它保证了应用中数据的平缓。比如,任何数据的变化只能通过 action 发出,这也就更加容易理解如何做到一旦数据变化就会影响整个应用了。

注意:

如果你看过了 Facebook 关于 Flux 的指南,你一定会注意到 Dispatcher 的概念。Dispatcher 是一个注册到 store 中的一个回调函数。当 action 被调用,Dispatcher 会响应它并且把相关的数据发送到所有注册的 store 中。Store 然后检查 action 的类型并且作出相应的反应。

上面的过程被一个叫做 Reflux 的类库很好的简化了。它通过使 actions 可监听去掉了 Dispatcher 的概念。所以,在 Reflux 中,store 可以直接监听 action 并且对他们需要的内容做出响应。

为了更好地理解 Flux 模式,我们使用 Reflux,React 和 Node.js 共同创建一个记事本应用。

搭建开发环境

我们会使用 React 和 Reflux 作为 Node 模块并且使用 Browserify 让它们在客户端同样可用。下面就介绍如何搭建环境:

  1. 我们会使用 Browserify 打包我们的 React 组件,Actions 和 Stores 被打包成一个客户端 .js 包。
  2. 我们会使用 grunt watch 监控上面的组件中的变化并且每次发生变化时都会重新运行 Browserify。
  3. grunt nodemon 被用于重启服务每当任何 .jsx 或者 .js 文件发生变化时,所以你不需要手动控制。

你可以从 GitHub 下载相关代码然后打开 Gruntfile.js 查看相关的任务。当你的机器上有了这个库,你仅仅需要运行 npm install 来安装所以来的所有 node 模块。运行下面的命令,然后开始开发:

grunt watch
grunt nodemon

这个应用可以在 localhost:8000 访问到。

使用这个应用

我们从这个应用不同的组件开始。下面是我们如何将我们的 UI 分成不同的组件:

下面是每个组件的功能:

  1. NoteApp:这是根组件,包含了两个子组件:NoteListBox 和 NoteCreationBox。
  2. NoteListBox:有一个子组件 NoteList。它会得到一个日记列表从 Flux Store 并且把它们传递到 NoteList。
  3. NoteList:负责渲染每个 Note 组件。传递一个 note 对象到每个 Note 组件中。
  4. Note:为一个单独的 note 项呈现具体内容。在这个例子中仅仅展示 title。你可以轻易的进入并且展示其他的细节像 date,subtitle 等。
  5. NoteCreationBox:这个组件渲染了一个 TextArea 组件,并且如果存在一个当前正在编辑的 日记 id,则传递给它。
  6. TextArea:提供一个 textarea 用于用户输入。传递日记的文本到 NoteCreationBox 中保存。

创建 Actions

我们使用 Reflux 创建一个 action。如果你打开了 actions/NoteActions.js,你会看到 action 是如何被创建的。下面是代码片段:


1

2

3

var Reflux = require(‘reflux‘);var NoteActions = Reflux.createActions([

  ‘createNote‘,

  ‘editNote‘]);module.exports = NoteActions;

Reflux.createActions 被用作创建 Action。我们导出这些 Action ,在组件中方便使用它们。

创建 Store

我们创建了一个叫做 NoteStore 的 store,用来维护日记队列。下面的代码用于创建 store(stores/NoteStore.js):


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

var Reflux = require(‘reflux‘);var NoteActions = require(‘../actions/NoteActions‘);var _notes = []; //This is private notes arrayvar NoteStore = Reflux.createStore({

  init: function() {

    // Here we listen to actions and register callbacks

    this.listenTo(NoteActions.createNote, this.onCreate);

    this.listenTo(NoteActions.editNote, this.onEdit);

  },

  onCreate: function(note) {

    _notes.push(note); //create a new note

    // Trigger an event once done so that our components can update. Also pass the modified list of notes.

    this.trigger(_notes); 

  },

  onEdit: function(note) {

    // Update the particular note item with new text.

    for (var i = 0; i < _notes.length; i++) {

      if(_notes[i]._id === note._id) {

        _notes[i].text = note.text;

        this.trigger(_notes);

        break;

      }

    }

  },

  //getter for notes

  getNotes: function() {

    return _notes;

  },

  //getter for finding a single note by id

  getNote: function(id) {

    for (var i = 0; i < _notes.length; i++) {

      if(_notes[i]._id === id) {

        return _notes[i];

      }

    }

  }});module.exports = NoteStore; //Finally, export the Store

可以看到,我们监听两个 action,createNote 和 editNote,在 init 方法中。同样,我们注册了回调函数当 action 被调用时。添加/更新日记的代码很简单。我们暴漏了 getter 用来获取日记列表。最后,store 被暴漏以便它可以在我们组件中使用。

创建组件

我们所有的 React 组件都位于 react/components 目录下。我已经展示了 UI 的所有结构。你可以看看下载的源代码,详细了解每个组件。这里我展示看最关键的一部分(例:我们的组件如何调用 action 以及如何与 store 交互)

NoteListBox:

这个组件从 NoteStore 获得了日记列表,并且把它们吐给 NoteList 组件然后渲染日记。这个组件看起来像下面这样:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

var React = require(‘react‘);

var NoteList = require(‘./NoteList.jsx‘);

var NoteStore = require(‘../../stores/NoteStore‘);

var NoteListBox = React.createClass({

  getInitialState: function() {

    return { notes: NoteStore.getNotes() };

  },

  onChange: function(notes) {

    this.setState({

      notes: notes

    });

  },

  componentDidMount: function() {

    this.unsubscribe = NoteStore.listen(this.onChange);

  },

  componentWillUnmount: function() {

    this.unsubscribe();

  },

  render: function() {

    return (

        <div className="col-md-4">

            <div className="centered"><a href="" onClick={this.onAdd}>Add New</a></div>

            <NoteList ref="noteList" notes={this.state.notes} onEdit={this.props.onEdit} />

        </div>

    );

  }

});

module.exports = NoteListBox;

当这个组件开始工作,我们就可以开始监听 NoteStore 的 change 事件。无论何时在这个日记列表中有变化时都会去广播。我们的组件监听这个事件以便它可以重新渲染这个日记当有任何的变化时。下面这行代码注册一个监听器:

this.unsubscribe = NoteStore.listen(this.onChange);

因此,无论什么时候发生了变化,组件的 onChange 方法都会被调用。这个方法接收到一个更新的日记列表然后改变 state。


1

2

3

this.setState({

  notes: notes //state changes

});

由于 this.state.notes 是作为一个 prop 被传递到 NoteList 中,只要 state 发生了变化 NoteList 都会重新渲染自己。

最后,我们在 componentWillUnmount 中添加了 this.unsubscribe() 用来移除监听器。

因此,这就是 NoteList 如何通过监听 Store 的 change 事件一直处于最新的原因。现在我们看一下一个日记如何被创建/编辑。

NoteCreationBox:

仔细看一下 NoteCreationBox 方法:


1

2

3

4

5

6

handleSave: function(noteText, id) {

  if (id) {

    NoteActions.editNote({ _id: id, text: noteText });

  else {

    NoteActions.createNote({ _id: Date.now(), text: noteText });

  }}

每当保存按钮被点击时这个方法都会被调用。它接受 noteText 作为它的第一个参数。如果 id 作为第二个参数被传递,我们知道这是一个编辑操作并且调用 NoteActions.editNote()。否则我们会为新的日记生成一个 id 并且调用NoteActions.createNote() 方法。记住 NoteStore 监听了这些 action。根据这个 action,正确的 store 回调被执行。一旦数据发生了更改,store 会触发一个 change 事件并且我们的 NoteList 组件会更新自己。

这就是在 Flux 应用中数据如何流入系统并且随后流出的。

为什么在服务端使用 React

你 可能好奇为什么在服务端使用 React 和 Reflux。React 最酷的一个特性就是可以在客户端和服务端渲染。使用这种技术,你可以创建同构的应用,在服务端渲染并且表现的和单页面应用一样。然而这对一个记事本应用不 是很必要,你可以轻松地使用这个方案创建一个复杂的同构的应用。

时间: 2024-10-10 17:27:03

使用 React 和 Flux 创建一个记事本应用的相关文章

React漫漫学习路之 利用Create React App命令创建一个React应用

所谓万事开头难,本文旨在为初探React的同学,建立第一个最基本的react应用. Create React App是Facebook官方的一个快速构建新的 React 单页面应用的脚手架工具,它可以帮你配置开发环境,以便你可以使用最新的 JavaScript 特性,还能提供很棒的开发体验,并为生产环境优化你的应用.(如果你使用过vue-cli构建vue应用,那么此处可类比) 话不多说,直接开始. 安装 全局安装create-react-app npm install -g create-rea

react用脚手架创建一个react项目

官网地址:https://react.docschina.org/ 确保本地安装了Node.js node的版本大于8.10    npm的版本大于5.6 1.在本地的某个位置创建一个文件夹,执行以下代码: npx create-react-app my-app(项目名称 可以自定义) 等待...... 创建好项目后,跳转到项目跟目录: cd my-app 然后运行项目: npm start 弹出这个页面代表项目已经创建好了! 原文地址:https://www.cnblogs.com/fqh12

翻译React官网文档—— 入门创建一个Hello World

React的初衷是一个用于构建View层(界面)的javascript类库.后来规模越来越多又有了ReactNative. 不赘述如何搭建react了,由于是学习我们直接用CodePen(可能需要FQ,可以自行下载免费的Lantern),Codepen中我们可以自由的修改代码 通常学习任何语言都要写一个Hello World.Tack is cheep 直接上代码 Go! ReactDOM.render( <h1>Hello, world!</h1>, document.getEl

【11】react 之 flux

Flux 是 Facebook 使用的一套前端应用的架构模式.React 标榜自己是 MVC 里面 V 的部分,那么 Flux 就相当于添加 M 和 C 的部分. 1.1.  Flux介绍 Flux并不是一项新的技术,而是一种架构模式,一个Flux应用由四个部分: View: 视图层(组件) Action(动作):视图层发出的消息(比如mouseClick) { type:'save', payload:'明天不能休息,自己在家把react弄一弄' } Dispatcher(派发器):用来接收A

Flux是一个Facebook团队的前端开发架构

Flux introduction 本文组成: React 官方文档翻译 相关实践心得. 内容上是Flux的介绍,例子将会在以后写出.一旦稍微多了解一点React,很难避免听到Flux这个名词.Flux是一个Facebook团队的前端开发架构.借助单向数据流等其它机制,使得React可以发挥了更加强大的功能.比起其它的框架,Flux更像是一种模式,我们可以投入较少的学习成本,快速上手Flux. Flux应用有三个主要的组成部分:调度者(dispatcher), 仓库(stores),视图(vie

jsWindow 对象 Window 对象 Window 对象表示浏览器中打开的窗口。 如果文档包含框架(frame 或 iframe 标签),浏览器会为 HTML 文档创建一个 window 对象,并为每个框架创建一个额外的 window 对象。 注释:没有应用于 window 对象的公开标准,不过所有浏览器都支持该对象。 Window 对象集合 集合 描述 frames[] 返回窗口中所有命

一.JSX简介 JSX就是Javascript和XML结合的一种格式.React发明了JSX,利用HTML语法来创建虚拟DOM.当遇到<,JSX就当HTML解析,遇到{就当JavaScript解析. 如下(JS写法) var child1 = React.createElement('li', null, 'First Text Content'); var child2 = React.createElement('li', null, 'Second Text Content'); var

创建一个提供数据 API 的 Node.js 网站

创建站点目录 首先,创建一个文件夹用来保存你的站点文件,使用 mkdir 就可以了 PS C:\> mkdir mysite 然后,进入到这个文件夹进行下一步的操作. 创建包说明 使用记事本或者你喜欢的任何纯文本编辑器创建 package.json 文件,文件名是一个约定必须是这个名字. 创建本网站自身的说明,说明依赖的其它包. { "name": "express-api", "version": "0.0.1", &

【转】浅谈React、Flux 与 Redux

本文转自<浅谈React.Flux 与 Redux>,转载请注明出处. React React 是一个 View 层的框架,用来渲染视图,它主要做几件事情: 组件化 利用 props 形成单向的数据流 根据 state 的变化来更新 view 利用虚拟 DOM 来提升渲染性能 前面说到 React 能够根据 state 的变化来更新 view,一般来说引起 state 变化的动作除了来自外部(如服务器),大部分都来自于页面上的用户活动,那页面上的用户活动怎样对 state 产生作用呢?Reac

react及flux架构范例Todomvc分析

react及flux架构范例Todomvc分析 通过分析flux-todomvc源码,学习如何通过react构建web程序,了解编写react应用程序的一般步骤,同时掌握Flux的单向数据流动架构思想 关于react react一个最吸引我的特性是组件,它是模块化的,所有的组件是独立的,又可以通过嵌套来构建更大型的组件,一个个小组件经过层层组装,最终形成web应用程序,它让我开始重新思考如何去构建大型的web应用程序. 关于Flux Flux是一个思想而非框架,强调数据自上而下传递的单向流动理念