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