关于ReactJS的概述

61 阅读9分钟

一个独特的卖点是ReactJS也可以在服务器端进行渲染,并且可以与客户端/服务器互操作。

为什么是React?

render()只是普通的javascript。你可以在你的渲染代码中获得JS的全部功能,而不是受制于你的模板语言所能做到的。你可以使用map、reduce、filter、groupBy等。

它是快速的(和本地DOM一样快,甚至比它更快)。

你不需要为了简单而放弃灵活性。你可以有

有了Flux,它推动了单向流动,减少了复杂性,增加了可预测性。

我喜欢jsx和组件(不是业务!)的逻辑只在一个文件中。

"可以说,在许多情况下,React比angular快得多。使用angular进行开发,你会遇到这样的情况:对于你的应用程序的要求来说,dirty-checking digest周期太慢。对于这些情况,一个相当简单的解决方案是使用ngReact。ngReact允许你在angular应用程序中包含React组件。我建立的第一个React组件是重写一个最初用angular编写的20个月的日历小部件。重写花了大约一天时间,这证明了React的学习曲线相当简单,而且ngReact也很简单。我甚至没有尝试在React组件中做任何shouldComponentUpdate()的优化,它的速度比angular对应的组件快了几倍。"- medium.com/@gilbox/How… and-flux-help-us-create better-stronger-fast-angular-applications-639247898fb

组件

  • 是React中最小但最基本的部分。它们类似于小部件和模块。
  • 在React中构建时,你需要从你能定义的最小的组件的角度来考虑它。

组件的生命周期

安装

  • componentWillMount:在渲染发生之前,在客户端和服务器端都调用一次。
  • componentDidMount:只在客户端调用一次(不在服务器上),在初始渲染发生后立即调用。在生命周期的这一点上,该组件有一个DOM表示,你可以通过this.getDOMNode() 。如果你想集成其他JS框架,设置定时器或间隔,或发送AJAX请求,在这个方法中执行这些操作。

更新

  • componentWillReceiveProps:当一个组件正在接收新的道具时被调用。这个方法在初始渲染时不被调用。利用这个机会,在render()被调用之前,通过使用this.setState()更新状态,对道具转换做出反应。
  • shouldComponentUpdate:当收到新的道具或状态时,在渲染前被调用。这个方法在初始渲染或使用forceUpdate 的时候不被调用。当你确定过渡到新的道具和状态不需要组件更新时,可以利用这个机会return false 。如果返回false,那么render()将被跳过,直到下一个状态变化。如果需要的话,这是一个可以进行性能改进的好地方,即。shouldComponentUpdate: function(nextProps, nextState){ return nextProps.id !== this.props.id; }
  • componentWillUpdate:当收到新的道具或状态时,在渲染前立即调用。这个方法不会在最初的渲染中被调用。利用这个机会,在更新发生之前进行准备。

卸载

  • componentWillUnmount:在一个组件从DOM上卸载之前立即调用。在这个方法中执行任何必要的清理工作,如无效的计时器或清理任何DOM元素,这些元素是在componentDidMount

props vs state

  • props和state都是普通的JS对象
  • 道具和状态的变化都会触发渲染更新
  • 道具和状态都是决定性的。如果你的组件对相同的props和state的组合产生不同的输出,那么你就做错了。
  • 如果一个组件需要在某个时间点改变它的一个属性,那么这个属性应该是其状态的一部分,否则它应该是该组件的一个道具。
道具状态
能否从父组件中获得初始值?是的是的
能否由父组件改变?是的不能
是否可以在组件内设置默认值?是的是的
能否在组件内部进行更改?不能是的
能否为子组件设置初始值?是的是的
是否可以改变子组件?是的不可以

道具

  • Props有点像一个组件的配置/选项。
  • 一个组件不能改变它的道具,但它要负责把它的子组件的道具组合起来。
  • 道具是由组件的父代传下来的,不能从组件本身以任何方式改变。
  • 当应用程序变得越来越大时,就很难记住哪些类型以及某个属性是否需要。请确保你使用propTypes 功能。
  • 为了减少以后的调试时间,确保你从一开始就编写严格的propTypes。
  • 样式属性不接受字符串。你可以指定JS对象,其键值与camelCase的CSS属性名称相对应。
  • 可以使用onClick和onChange等属性来分配事件

设置属性类型

propTypes: {
    name: React.PropTypes.string,
    visible: React.PropTypes.bool.isRequired,
    before: function(properties, propertyName, componentName){
        if(!(propertyName in properties)){ throw Error(‘Property `before` must be set.’)}
    }
}

设置默认属性

getDefaultProps: function(){
    return { ‘firstName’:’JC’, ‘lastName’:’Viray’ }
},
render: function(){
    return <div> hello {this.props.firstName} </div>
}

状态

  • state 是在组件本身中创建的。
  • 一个state ,应该被认为是私有数据。
  • 一个状态从组件安装时的默认值开始,然后在时间上遭受突变(主要由用户事件产生)。
  • 一个状态是可选的。因为它增加了复杂性并降低了可预测性,所以没有状态的组件是最好的。 尽量避免有状态
  • 一个状态应该在一个时间点上是可序列化的--一个快照。
  • 一个组件在内部管理自己的状态,但除了设置一个初始状态外,没有必要对其子代的状态进行摆弄。
  • 与道具不同的是,状态可以从组件内部被改变。
  • 今天,软件工程界的普遍共识是要避免易变的状态。这是好的React组件设计的第一原则。如果可能的话,尽量避免将状态放在组件内部。
  • state 在组件中的状态只应在组件定义中看到。作为组件的开发者,你应该是唯一知道你的组件需要什么状态以及应该接受/提供的正确数据类型的人。
  • 请注意,对状态的使用应该是尽可能有限的。当你使用状态时,你有可能在你的组件的行为和渲染中引入一些错误。

设置初始状态

getInitialState: function(){
    return { ‘firstName’:’JC’, ‘lastName’:’Viray’ }
}

更新状态

var Component = React.createClass({
    getInitialState: function(){
        return { name: ‘Chris’};
    },
    handleClick: function(){
        this.setState({ name: ‘Bob’ });
    },
    render: function(){
        return <div onClick={this.handleClick}> hello {this.state.name} </div>
    }
});

React.renderComponent(
    <InterfaceComponent />,
    document.body
)

用React思考问题

第一步:将UI分成一个组件层次

你要做的第一件事是在mock中的每个组件和子组件周围画上方框,并给它们都起个名字。使用单一责任原则,也就是说,一个组件最好只做一件事。如果它最终成长起来,应该被分解成更小的子组件。

第二步:在React中建立一个静态版本

拿出你的数据模型,建立没有交互性的用户界面。这通常需要大量的输入,而不需要思考。

为了建立一个静态版本的应用程序,你要建立重用其他组件的组件,并使用props传递数据。props是一种从父代到子代传递数据的方式。在这里,你根本不打算使用状态。状态只保留给互动性,也就是随时间变化的数据。

在这一点上,你将会有可重用的组件,利用你的模拟数据模型的道具,并且将只有render()方法。

第3步:确定UI状态的最小但完整的表示方法

为了使你的用户界面具有交互性,你需要能够触发对你的底层数据模型的改变。在这里,你将使用状态。

为了正确地构建你的应用程序,你首先需要思考你的应用程序所需要的最小的可改变的状态集。

注意:弄清楚你的应用程序需要的绝对最小的状态表示,并按需计算你需要的其他一切。例如:如果你正在建立一个 "待办事项列表",只需保留一个待办事项的数组;不要为计数保留一个单独的状态变量。相反,当你想呈现todo计数时,只需取todo项目数组的长度。记住尽量少用状态变量

在我们的示例程序中,这里是我们的数据。

  • 原始的产品列表(prop...被传递,所以不是一个状态)
  • 用户输入的搜索文本(状态...随时间变化,无法计算)。
  • 复选框的值(状态......随时间变化,无法计算)。
  • 过滤后的产品列表(既不是,因为它可以被计算出来)。

第四步:确定你的状态应该在哪里。

现在你已经确定了应用程序状态的最小集合是什么,你需要确定哪些组件会改变或拥有这些状态。

记住,React是所有关于 "单向 "数据流的组件层次结构。可能不会立即清楚哪个组件应该拥有这个状态。

对于你的应用程序中的每一块状态,按照以下步骤来弄清楚。

  • 确定每一个基于该状态进行渲染的组件
  • 找到一个共同的所有者组件(在层次结构中需要该状态的所有组件之上的一个组件)
  • 共同所有者或层次结构中更高的另一个组件应该拥有该状态。
  • 如果你找不到一个有意义的组件来拥有这个状态,那么就创建一个新的组件,只是为了持有这个状态,并把它添加到层次结构中共同所有者组件之上的某个地方。

第5步:添加反向数据流

现在是支持数据反向流动的时候了。最好的方法是,父类向子类的onChange处理程序传递一个回调,子类将信息传递给该处理程序。

关于Flux的快速介绍

"Flux "这个名字是一个自命不凡的理解障碍。没有所谓的Flux。Flux是一个概念,不是一个库。好吧,有一个库,有点像。"

"Flux更像是一种模式,而不是一个框架"

""Flux "的概念只是你的视图触发了一个事件(例如,当用户在一个文本字段中输入一个名字后),该事件更新了一个模型,然后该模型触发了一个事件,而视图通过重新渲染最新的数据对该模型的事件做出反应。就是这样。"