近来React.js变得越来越流行,本文就来谈一谈React.js的入门实践,通过分析一些常用的概念,以及提供一些入门 的最佳编程编程方式,仅供参考。

首先需要搞懂的是,React并不是一个框架,React提供了一些新颖的概念、库 和编程原则让你能够同时在服务端和客户端编写快速、紧凑、漂亮的代码来构建 你的web应用。

如果你使用React,那么可能会涉及到一些常用的概念或技术,包括:

  • ES6 React
  • 虚拟DOM(virtual DOM)
  • 组件驱动开发(component-driven development)
  • 不变性(immutability)
  • 自上而下的渲染(top-down rendering)
  • 渲染路径和优化
  • 打包工具, ES6, 构建请求, debugging, 路由等
  • 同构React(isomorphic React)

什么是React.js

React.js不是一个框架

在整个Web应用的MVC架构中,你可以将React看作为视图层,并且是一个高效 的视图。React提供了和以往不一样的方式来看待视图,它以组件开发为基础。 对React应用而言,你需要分割你的页面,使其成为一个个的组件。也就是说,你的 应用是由这些组件组合而成的。

你可以通过分割组件的方式去开发复杂的页面或某个功能区块,并且组件是可以 被复用的。这个过程大概类似于用乐高积木去瓶装不同的物体。我们称这种编程方式称为 组件驱动开发。

React的一大特点是其所拥有的虚拟DOM,它让页面渲染变得非常的高效,并且比直接 操纵DOM变得更为可控。这两大特点的组合使得React具有强大的自上而下的页面渲染 能力。

好了,React的有两个特点:组件化和高效的虚拟DOM,但是为什么它这么被看好呢? 因为React更多的是一种概念层面的东西,而库是其次的。也有很多其他遵从了这些思想的第三方实现。和每一个编程概念一样,React尤其 独有的解决方案、工具和工具。但这里并不会深入的去讨论他们,而是关注React本身。

Virtual DOM

为了跟踪模型层的变化,并且将其应用到DOM中(也就是渲染),我们需要注意两个 重要的事情:

  1. 数据是什么时候改变的
  2. 哪一个(些)DOM元素需要被更新

对于(1)而言,React提供了一个观察者模型用于替代传统的脏检查(dirty checking), 也就是持续的检查模型的变化。这也就是解释了为什么React不需要计算哪些发生 了改变的原因,因为它会立即知道。这个过程减少了计算量,并它应用程序变得 更平滑。但这里真正有趣的是,React是如何管理DOM操纵的。

对于DOM改变(2)而言,React在内存中构建了DOM的树形表示,并且计算出哪个 DOM元素应该被改变。对浏览器而言,DOM操纵是比较耗费性能的,因此我们更倾向于 让其变得最小化。幸运的是,React视图尽可能少的触及到DOM元素。给予对象表示而言, 更少的DOM操纵意味着计算会更快,因此DOM改变也被尽可能的减少。

React在底层实现了一个diffing算法,该算法使用DOM的树形表示法,当某个 节点发生变化(标记为dirty)时它会重新计算整个子树,你会注意到你的模型发生 了改变,因为整个子树在之后会被重新渲染。关于该算法的详细分析可以参考这篇 文章

如何在服务端渲染

因为React在DOM表示时使用了一个虚拟(假的)DOM,因此借助于这种方式使得在服务端 渲染输出HTML称为可能(不借助于JSDom, PhantomJS等)。React还能智能的识别出 服务端渲染出来的页面标记,并在客户端只为这些标记添加事件处理器,这对构建 同构web app非常有用。

有意思的是,React渲染出来的HTML标记都包含了data-reactid属性,这有助于 React中追踪DOM节点。

一些阅读资料

  1. React’s diff algorithm
  2. The Secrets of React’s virtual DOM
  3. Why is React’s concept of virtual DOM said to be more performant than dirty model checking?
  4. virtual-dom

组件驱动开发

对于component-driven development而言,你在一个模板中是看不到整个网站的。 虽然在一开始你可能会遇到一些困难,但是如果进一步的使用这种思路,你会发现 它易于理解,易于维护,并且容易测试。

如何使用React的方式来思考组件开发

下面我们来看如何实现组件驱动开发这一理念。我们看一个例子,这个例子来源于 thinking in react 这篇文章。对于构建一个可过滤的产品列表而言,通常其包括如下的组件结构:

  • FilterableProductTable

    • SearchBar
    • ProductTable
      • ProductCategoryRow
      • ProductRow

一个组件应该包含什么

首先,理想的,我们应该遵守单一责任原则 来设计你的组件。当你发下你的组件应该做的更多的时候,你可以考虑将其分割为 更小的组件集合。

因为我们在讨论组件层级,因此在你的组件中也会使用到其他组件。我们首先看下 在ES5中组件代码是什么样子的:

var HelloComponent = React.createClass({
render: function() {
return <div>Hello {this.props.name}</div>;
}
});

如果使用ES6,你的组件代码可以这样写:

class HelloComponent extends React.Component {
render() {
return <div>Hello {this.props.name}</div>;
}
}

  

JS和JSX

正如你说看到的,我们的组件是JS和HTML代码的混合,你可能会觉得这很糟糕,因为 MVC一直在教我们尽可能的隔离视图和控制逻辑。但另一方,这种混合获得另一个层面的 单一责任,他使得组件更加的灵活和可重用。

当然,在React中你也可以使用纯JS来编写你的组件:

render () {
return React.createElement("div", null, "Hello ",
this.props.name);
}

  

是的,你会发现这很麻烦,没有使用HTML来得直观。因此React提供了JSX (JavaScript eXtension)语法让你能够在JS中书写HTML代码。

render () {
return <div>Hello {this.props.name}</div>;
}

什么是JSX

JSX在ECMAScript的基础上提供了类似于XML的扩展。 JSX和HTML有点像,但也有不一样的地方。例如,HTML中的class属性在JSX中 为className。其他不一样的地方,你可以参考FB的 HTML Tags vs. React Components这篇文章。

但是由于浏览器原生并不支持JSX,因此我们需要将其编译为JS,有很多方法能够 完成这个任务,后面我们会提到这些方法。此外,Babel也能够讲JSX编译为JS。

一些参考资料:

  1. JSX in depth
  2. Online JSX compiler
  3. Babel: How to use the react transformer

组件还应该包括什么

每个组件都应该包括一些内部状态,处理逻辑,和事件处理器(例如按钮点击、输入改变), 当然也包括一些内部的样式。

你会遇到{this.props.name}这样的代码片段,这意味着你可以通过属性的方式 先组件内传递数据,例如<MyComp name='weiwei sun' />。这让组件变得可重用, 并且能够自上而下的向嵌套的组件传递数据。

示例代码如下:

class UserName extends React.Component {
render() {
return <div>name: {this.props.name}</div>;
}
} class User extends React.Component {
render() {
return <div>
<h1>City: {this.props.user.city}</h1>
<UserName name={this.props.user.name} />
</div>;
}
} var user = { name: 'John', city: 'San Francisco' };
React.render(<User user={user} />, document.body);

React拥抱ES6

在React中尝试编写ES6是个非常不错的开始,React并不是一开始就支持ES6的, 而是从v0.13.0开始支持的。你会经常用到的ES6特性包括类、箭头函数、consts 和模块。例如,我们会经常从继承React.Component类开始编写我们的组件。

还有一点需要注意的是,并不是每个浏览器都支持ES6,因此目前情况下,我们需要 使用一些工具将我们编写的ES6代码转换为ES5代码,我推荐使用 Babel

一些参考资料:

  1. Babel: Learn ES6
  2. React ES6 announcement

组件生命周期

每个React组件在加载时都有特定的生命周期,在此期间不同的方法会被执行。 下面简单介绍React组件的生命周期:

componentWillMount

该方法会在组件render之前执行,并且永远只执行一次。

componentDidMount

该方法会在组件加载完毕之后立即执行。此时,组件已经完成了DOM结构的渲染, 并可以通过this.getDOMNode()方法来访问。

componentWillReceiveProps

组件接收到一个新的prop时会被执行,且该方法在初始render时不会被调用。

shouldComponentUpdate

在组件接收到新的props或state时被执行。

componentWillUpdate

在组件接收到新的props或者state但还没有render时被执行。 在初始化时不会被执行。

componentDidUpdate

在组件完成更新后立即执行。在初始化时不会被执行。 一般会在组件完成更新后被使用。

componentWillUnMount

在组件从DOM中unmount后立即执行。该方法主要用来执行一些必要的清理任务。

关于生命周期的具体内容,你可以参考官方文档

在打包时使用Webpack和Babel

我们会经常用到一些工具,首先一个是node.js的模块系统和它的包管理工具npm。 我们会编写node风格的代码来require我们需要的东西。并且react本身也是一个独立的 npm包。

通常你有两种选择,commonJS或者ES6:

var React = require('react/addon');

var MyComponent = React.createClass({
// do something
}); module.exports = MyComponent;

或者

import React from 'react/addons';
class MyComponent extends React.Component {
// do something use es6
}
export default MyComponent;

例如,我们会使用debug模块来调试, 使用superagent模块来编写请求。

现在,我们有了Node的依赖管理系统,并且使用npm来提供模块。下面我们需要做的 事:选择一个合适的库来打包我们的代码,并且能够让其运行在浏览器上。

因此我们需要一个打包器。目前最流行的解决方案包括两个,分别是Browserify和 Webpack。我们选择使用Webpack,因为Webpack 更适合于React社区。

Webpack是如何工作的

Webpack用于打包我们的代码,并且包含进我们需要的包,然后输出为浏览器可运行的 文件。因为我们使用JSXES6,因此我们需要相应的工具来将其转换为ES5。事实上, Babel能够同时做这两件事。使用Webpack能够很轻松的完成这些任务,因为Webpack 是面向配置的。

使用如下命令开始:

npm init
npm install webpack --save-dev
npm install babel --save-dev
npm install babel-loader --save-dev

然后创建webpack.config.js文件,我们需要使用ES5来编写该文件,因为它是 webpack的配置文件。一个典型的配置方式如下:

var path = require('path');

module.exports = {
entry: path.resolve(__dirname, '../src/client/scripts/client.js'),
output: {
path: path.resolve(__dirname, '../dist'),
filename: 'bundle.js'
}, module: {
loaders: [
{
test: /src\/.+.js$/,
exclude: /node_modules/,
loader: 'babel'
}
]
}
};

运行webpack命令你可以执行打包流程。这之后你可以只在页面中包含bundle.js即可。 如下:

<script src='bundle.js'></script>

(提示:你可以使用node-static来存放你的静态资源文件,使用npm install -g node-static 来安装,并使用static .来启动)。

项目结构

一个典型的项目结构你可以参考这个仓库

config/
app.js
webpack.js (js config over json -> flexible)
src/
app/ (the React app: runs on server and client too)
components/
__tests__ (Jest test folder)
AppRoot.jsx
Cart.jsx
Item.jsx
index.js (just to export app)
app.js
client/ (only browser: attach app to DOM)
styles/
scripts/
client.js
index.html
server/
index.js
server.js
.gitignore
.jshintrc
package.json
README.md

如何测试React组件

对于React组件的测试,这里推荐使用Jest, Jest也是由Facebook提供的测试框架,并且有很多强大的特性,但这里并会详细的 介绍它们。

关于Jest,我推荐你阅读和尝试来自Facebook的Tutorial

对于ES6代码的测试,你可以参考 React ES6 Testing

小结

本文简单介绍了React的基础原理,一些相关的编程技术。后续还会整合一些资料 谈一谈Flux和同构。

Statement

本文翻译自:https://blog.risingstack.com/the-react-way-getting-started-tutorial/ 有增删改。

References

  1. https://blog.risingstack.com/the-react-way-getting-started-tutorial/
  2. https://github.com/RisingStack/react-way-getting-started
  3. http://facebook.github.io/react/docs/component-specs.html

谈谈 React.js 的核心入门知识的更多相关文章

  1. React.js 官网入门教程 分离文件 操作无法正常显示HelloWord

    对着React官网的教程练习操作,在做到分离文件练习时,按照官网步骤来却怎么也无法正常显示HelloWord. 经测试,html文件中内容改为: <!DOCTYPE html><ht ...

  2. React.js 三周 -- 入门到搭建团队基础项目

    吐槽 公司自己的产品,由于历史遗留问题,前端一直是和java放到一个项目里写的. 导致了,前端就被死死的绑在了IDEA战车上.想要看页面效果,先起几个java服务.想要调试一个改动,重启个java服务 ...

  3. JS基础一-入门知识

    一.什么是JavaScript JavaScript是一种基于对象和事件驱动并具有安全性能的解释性脚本语言.JavaScript不需要编译,直接嵌入在HTTP页面中,把静态页面转变成支持用户交互并响应 ...

  4. 【每天半小时学框架】——React.js的模板语法与组件概念

           [重点提前说:组件化与虚拟DOM是React.js的核心理念!]        先抛出一个论题:在React.js中,JSX语法提倡将 HTML 和 CSS 全都写入到JavaScrip ...

  5. React.js入门笔记

    # React.js入门笔记 核心提示 这是本人学习react.js的第一篇入门笔记,估计也会是该系列涵盖内容最多的笔记,主要内容来自英文官方文档的快速上手部分和阮一峰博客教程.当然,还有我自己尝试的 ...

  6. React的入门知识与概念【1】

    回顾在以往的项目开发中,从最初的使用的原生html+js+css+jquery开发,到后来随着项目功能的增加,也渐渐学习了Vue.js框架的开发,以及Vue.js的全家桶Axios,Vue-route ...

  7. React.js入门

    React 入门实例教程   现在最热门的前端框架,毫无疑问是 React . 上周,基于 React 的 React Native 发布,结果一天之内,就获得了 5000 颗星,受瞩目程度可见一斑. ...

  8. React.js入门笔记(再续):评论框的实现

    本案例来自React.js中文官网对应内容. 一. 运行环境 <link rel="stylesheet" type="text/css" href=&q ...

  9. Facebook React.js库 入门实例教程

    作者: 阮一峰 日期: 2015年3月31日 现在最热门的前端框架,毫无疑问是 React . 上周,基于 React 的 React Native 发布,结果一天之内,就获得了 5000 颗星,受瞩 ...

随机推荐

  1. vim 学习日志(3):跳到行尾、行首、文件尾、文件首、加密

    vi操作: 1.跳到文本的最后一行:按“G”,即“shift+g” 2.跳到最后一行的最后一个字符 : 先重复1的操作即按“G”,之后按“$”键,即“shift+4”. 3.跳到第一行的第一个字符:先 ...

  2. git 常用命令 (git did not exit cleanly)

    Git常用操作命令收集: git clonegit git remote -v git remote add [name] [url] git remote rm [name] git remote ...

  3. 利用Hadoop实现超大矩阵相乘之我见(一)

    前记 最近,公司一位挺优秀的总务离职,欢送宴上,她对我说“你是一位挺优秀的程序员”,刚说完,立马道歉说“对不起,我说你是程序员是不是侮辱你了?”我挺诧异,程序员现在是很低端,很被人瞧不起的工作吗?或许 ...

  4. 基于spring-redis发布订阅模式的实现

    redis配置: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http ...

  5. 微信企业号开发--手机删除键keyup事件无效

    $('#input').keyup(function(){}); 其他的按键都是有效的,但是唯独删除按键无效. 以下方法可以解决: $('#input').bind('input propertych ...

  6. 解决WinForm(C#)中MDI子窗体最大化的问题

    “用MDI方式打开一个子窗口体后,总是不能最大化显示,明明子窗口体的WindowState设置为Maximized?”,相信有很多人会遇到这的样问题,请按下面的方法设置即可使MDI子窗体最大化: 1. ...

  7. 第二章 I - The 3n + 1 problem(2.4.2)

    这是一道很坑爹的题,一定注意输入的两个数的大小,并且不能简单的交换,因为在最后的输出的时候还需要将原来的数按照原来的顺序和大小,这就是为什么还得开辟两个值得原因 Description Problem ...

  8. Android Eclipse 里面依赖工程无法关联源码解决方案

    android开发中,debug调试是一种非常实用快速定位问题的办法.eclipse中多工程依赖状态下会偶现无法debug的困扰,debug中的代码执行时会报出如下错误  The JAR of thi ...

  9. 菜鸟学sql,Oracle数据库结构比较

    转载自:http://www.cnblogs.com/tianqing/archive/2008/06/25/1229419.html 做oracle下数据库结构比较,比较具体详细差异,例如:2个库具 ...

  10. python读取数据库数据,读取出的中文乱码问题

    conn = pymysql.connect( host='127.0.0.1', port=3302, user='username', passwd='password', db=database ...