查看原文
其他

[翻译]React最佳实践与实用函数

2016-09-20 iamcxa 前端圈

本文翻译自 Nessim Btesh 的好文章 React Best Practices and Useful Functions


React 近来已经成为一种被开发者用来建立从单页式应用程序、到移动端应用程序的新工具。但是,自从我越来越深入 React,我发现所有感觉很厉害的 Node modules 都写得不怎么样。这些 modules 几乎没有遵循任何规则,component 都太庞大了。


它们几乎把所有东西都放进 state 里,同时也没有善用 dumb component 带来的正面效益。有足够经验的人,都知道每次渲染时都管控每一个 component 的状态对浏览器来说是多大的负载。在本文中,我会带你实践几个让 React 做得快又好的最佳实践案例。


写在开始之前:请注意 React 是一种 functional programming (FP) 函数库。如果你不了解什么是 FP,请先阅读这篇 StackExchange response

http://stackoverflow.com/questions/128057/what-are-the-benefits-of-functional-programming


使用 ES6(由Babel转译):

ES6 会让你(在JS世界里)活得更轻松写意。它让 JavaScript 用起来、看起来更潮。


几个绝佳的 ES6 使用范例是 Generators 以及 Promises。还记得你需要做一大堆的 callback 才能正常执行一段异步的呼叫吗?嗯,现在我很荣幸的为你介绍 —— “同步的异步 JS”,一个很棒的范例是使用 generators

getJSON(url, function(response) {
   getJSON(url, function(response) {
     console.log(response);
   });
});

可以写成:

function* getStockValue() {
   var entry1 = yield request('http://myrl.com/stock/key');
   var data1  = JSON.parse(entry1);
   var entry2 = yield request('http://myurl/stock/value');
   var data2  = JSON.parse(entry2);
}

使用 Webpack:

让你决定使用 Webpack 的理由很简单:Hot reloading, minified files, node modules。而且,你可以把你的整个应用程序分装成小区块,并且 lazy load 它们。


永远注意你的 bundle 文件大小:

一个关于保持你的 bundle 纤细苗条的注意点是,直接从 node module 的跟目录 import 你需要的东西。


例如,原本这样做:

import {Foo} from ‘foo’

但其实该这样做:

import Foo from ‘foo/Foo’

使用 JSX:

如果你有 Web 的开发背景,JSX 格式会让你觉得再自然不过。如果你并没有相关背景,也不要担心,因为JSX 很好学。


请注意,如果不使用 JSX,你的应用程序会很难维护。


确保你的 Component 很小:

经验法则是:如果你的 render() 函数有超过 10 行,那应该这个 component 就是太大了。


整个运用 React 的中心思想是程序代码必须有足够的可重用性,所以如果你把所有东西都扔进同一个文件,那你就体会不到 React 之美了。


使用 ShouldComponentUpdate():

React 是一种当一个 component props/state改变时都重绘的模板语言。所以,想象如果你每次都要在某个 action 里重绘整个页面,将会给浏览器带来相当大的负荷。


这也就是 ShouldComponentUpdate() 为何而来。每当 React 需要重绘页面时,都会检查看看 shouldComponentUpdate 回传值是 false/true。所以,如果你有个静态的、不需要变动的 component,就回传 False 吧。或是,如果它不是纯静态的,那依据它的 props/state 是否改变来决定回传值。


使用 Smart 以及 Dumb Component 概念:

不需要让每个对象都有自己的 state。理想的情况下,你会有一个聪明的(smart) parent view,以及一大堆附属于它的 dumb component。后者并不包含任何逻辑,只负责接收由 parent 传来的 props


可以做一个 dumb component

const DumbComponent = ({props}) => {
 return (<div />);
}

Dumb component 相对来说比较好除错,因为它是一种强迫性的、由上而下的方法;同时,也是 React 的全部。


永远在构造器(constructor)中绑定(bind)函数(function):

每当新建一个有 state compoment 时,应该试着在构造器(constructor)中绑定(bind)函数(function)

export default class BindFunctionExample extends React.Component {
   constructor() {
       super();
       this.state = {
           hidden: true,
       };
       this.toggleHidden = this.toggleHidden.bind(this);
   }

   toggleHidden() {
           const hidden = !this.state.hidden;
           this.setState({hidden})
   }
   render(){
       return(
           <button onClick={this.toggleHidden} />
       )
;
   }

}

使用 Redux/Flux:

处理数据时,Redux/Flux 让你更轻易的处理数据,也让你跟处理前端快取的痛苦说再见。我个人使用 Redux,因为它强迫你必须有一个更好控制的文件结构。


使用 normalizr:

为你介绍处理复杂数据方面的圣杯:Normalizr,它可以动态地把你巢状的 JSON 对象简化成比较简单的结构。


使用 Containers:

你应该使用 containers 的理由是:向下传递数据。因为当应用 Flux/Redux 时,你会想要避免让每个 view 都跟 store 有连结。


建立两个 containers 可能是最好的方式,一个包含所有的 secure views(意指所有需要认证/授权的 view),另外一个则包含全部的 insecure views


建立 parent container 最好的方式是:clone 子组件,并且把需要的 props 传递下去。例如:

class Container extends React.Component {
 render(){
   var { props } = this;
   return(
     <div className="main-content">
     {  
       React.Children.map(this.props.children, function(child) {
         return React.cloneElement(
           child,
           { ...props }
         );
       })
     }
     </div>
   )
;
 }
}

const mapStateToProps = (state) => {
 return state;
};

function mapDispatchToProps(dispatch) {
 return {
   actions: bindActionCreators(actions, dispatch)
 };
}

export default connect(
 mapStateToProps,
 mapDispatchToProps
)(Container);

其他:

我想强调的是,应该把所有的 component 分割成独立的单一文件。


使用 router:

如果你要做一个单页面 App ,就需要一个 router。我个人使用 React Router

如果你使用 flux,记得要 unbind change events store listening,否则易造成 memory leaks 吧。


如果你想要动态的更改你应用程序的标题,你可以类似这样做:

componentDidMount(){
 document.title = "Store Profile"
}

这里有一个很棒的React/Redux 认证的范例:

https://github.com/joshgeller/react-redux-jwt-auth-example


使用 helper 函数:

以下是个比较对象的函数,用法:当 state/props shouldComponentUpdate() 周期变更时触发。

export const isObjectEqual = (obj1, obj2) => {
   if(!isObject(obj1) || !isObject(obj2)) {
       return false;
   }

   if (obj1 === obj2) {
      return true;
   }

   const item1Keys = Object.keys(obj1).sort();
   const item2Keys = Object.keys(obj2).sort();

   if (!isArrayEqual(item1Keys, item2Keys)) {
       return false;
   }

   return item2Keys.every(key => {
      const value = obj1[key];
      const nextValue = obj2[key];

      if (value === nextValue) {
          return true;
      }
      return Array.isArray(value) &&
          Array.isArray(nextValue) &&
          isArrayEqual(value, nextValue);
   });
};

动态地产生 reducer:

export function createReducer(initialState, reducerMap) {
 return (state = initialState, action) => {
   const reducer = reducerMap[action.type];
   return reducer
     ? reducer(state, action.payload)
     : state;
 };
}

用法:

import {createReducer} from '../../utils';
// Add the following for IE compatability
Object.assign = Object.assign || require('object-assign');

const initialState = {
 'count': 0,
 'receiving': false,
 'pages': 0,
 'documents': []
};

export default createReducer(initialState, {
 ['RECEIVED_DOCUMENTS']: (state, payload) => {
   return {
     'count': payload.count,
     'pages': payload.pages,
     'documents': payload.documents,
     'receiving': false
   };
 },
 ['RETRIVING_DOCUMENTS']: (state, payload) => {
   return Object.assign({}, state, {
     'receiving': true
   });
 }
});


【React启蒙系列文章】

一、[React启蒙系列] 初探React

二、[React启蒙系列] 学习React前需要理解的名词

三、[React启蒙系列] React和Babel的基本使用

四、[React启蒙系列]React节点

五、[React启蒙系列]使用JSX

六、[React启蒙系列]React 组件属性

七、[React启蒙系列]React 组件状态


【您可能感兴趣的文章】

一、手把手教你用react

二、React入门及资源指引

三、利用ESLint检查代码质量

四、构建一个安全的 JavaScript 沙箱

五、入门Webpack,看这篇就够了

六、第三届CSS大会广州找场地啦~~求介绍~~

七、Web Components 是个什么样的东西

八、JavaScript 被忽视的细节

九、[心得] 如何提高 React App 的性能

十、[心得] 自己动手打造 ES7 开发环境

十一、[译文] 如何运用新技术提升网页速度和性能

十二、你应该知道的HTTP基础知识

十三、Webpack from First Principles

十四、没时间阅读?佐克伯、比尔盖兹、马斯克教你「5小时原则」

十五、没快速成长,别说你在创业

十六、TCP三次握手&Render Tree页面渲染=>从输入URL到页面显示的过程?



前端圈--打造专业的前端技术会议

为web前端开发者提供技术分享和交流的平台

打造一个良好的前端圈生态,推动web标准化的发展

官网:http://fequan.com

微博:fequancom | QQ群:41378087


长按二维码关注我们

投稿:content@fequan.com

赞助合作:apply@fequan.com

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存