React.js的经验教训和一些有观点的最佳实践。这是我从React.js开发中所学到的所有东西的一个持续的汇编和进行中的工作。
基本组件组织
React.createClass({
propTypes: {},
mixins: [],
getInitialState(){},
getDefaultProps(){},
componentWillMount(){},
componentWillReceiveProps(){},
// Store removeChangeListener
componentWillUnmount(){},
// Third-party code initialization here...
// Store addChangeListener here...
componentDidMount(){},
_parseData(){},
_onSelect(){},
_onChange(){},
render(){}
});
Flux模式技巧
商店
- 存储器不一定只代表数据。它们也可以代表应用程序的状态,如模版是否显示/隐藏,或用户是否在线/离线等。
- 商店可以而且可能需要使用来自其他商店的数据。在调度器中使用waitFor方法。
- 商店不应该包含在服务器上获取自己的逻辑;最好是使用DAO(数据访问对象)来获取数据,它是薄层包装的API对象。
行动
- 行动应该被分成两种类型:视图行动和服务器行动。这将把用户交互(如点击按钮)与检索数据分开。
- 动作应该是 "发射 "和 "遗忘 "的,不能有回调。如果你需要对一个动作的结果做出反应,你应该监听一个完成或错误事件。
个人头脑风暴
专注于公共动作。简单性是关键。不要把执行放在最前面。
对于react来说,虽然它促进了一个在架构上更合理的应用,但由于html和javascript的耦合,它确实促进了难以管理的代码。HTML文件越来越大,主要是因为HTML的冗长,而逻辑和模块界面很容易在这个过程中丢失。
使用传播操作符,让孩子继承父母的道具。注意,这里的规范顺序很重要。后面的属性会覆盖前面的属性。
var props = { foo: 'default' };
var component = <Component {...props} foo={'override'} />
使用命名的组件,使组件更简单,更容易阅读。
var MyFormComponent = React.createClass({});
MyFormComponent.Row = React.createClass({});
MyFormComponent.Label = React.createClass({});
MyFormComponent.Input = React.createClass({});
//...
var Form = MyFormComponent;
var App = (
<Form>
<Form.Row>
<Form.Label />
<Form.Input />
</Form.Row>
</Form>
);
状态
对状态的道具进行重复的问题
这是一个有些复杂的事情。进入状态的东西会变得更加复杂,因为有可能要复制道具......这样就可以在表单中进行编辑。
setState不能处理复杂的对象,使得{ data:{}, errors:{}}不是一个可行的架构,怎么办?现在该如何处理表单呢?
一定有更好的方法......React.addons.update不应该被使用。它是不方便的,而且是一个黑客。
状态应该只是一个单层对象。它不应该有孙子,否则它将变得不可维护。有更多的反应模块比不方便的代码更好。
有意见的约定
JSX转换的内联迭代。过多的移动光标等会降低流程。但是部分可以被划分为变量。
组件应该尽可能地转储。所有的逻辑都应该存在于商店或服务中。组件必须包含的唯一东西是行动、事件处理程序和HTML。组件真的只是愚蠢的视图。
现在,巨大的htmls和表单怎么办?这些东西应该如何划分?
探索不同的架构
将布局代码作为道具分开
- 我喜欢顶层元素的类名与模块名相同的做法,这样在浏览器控制台调试时可以更好地查看。
- 我喜欢这个模块对风格的要求。风格惯例很好,非常好的BEM格式。
require('./DefaultLayout.less');
var DefaultLayout = React.createClass({
propTypes: {
header: React.PropTypes.node,
title: React.PropTypes.node,
content: React.PropTypes.node
},
render: function(){
return (
<div className="DefaultLayout">
<div className="DefaultLayout-header navbar navbar-default">
<div className="container">{this.props.header}</div>
</div>div>
// etc...
</div>
);
}
});
独立的渲染组件。对大的渲染函数说 "不"。
render: function(){
// ...
return (
<div className={classes}>
<div className="Item-title">
{this.renderTags()}
{this.renderDate()}
</div>
</div>
);
},
renderTags: function(){
return (
<div></div>
);
},
renderDate: function(){
return (
<div></div>
);
}