react组件设计原则_React组件设计技巧

React组件设计

组件分类

展示组件和容器组件

展示组件

容器组件

关注事物的展示

关注事物如何工作

可能包含展示和容器组件,并且一般会有DOM标签和css样式

可能包含展示和容器组件,并且不会有DOM标签和css样式

常常允许通过this.props.children传递

提供数据和行为给容器组件或者展示组件

对第三方没有任何依赖,比如store 或者 flux action

调用flux action 并且提供他们的回调给展示组件

不要指定数据如何加载和变化

作为数据源,通常采用较高阶的组件,而不是自己写,比如React Redux的connect(), Relay的createContainer(), Flux Utils的Container.create()

仅通过属性获取数据和回调

null

很少有自己的状态,即使有,也是自己的UI状态

null

除非他们需要的自己的状态,生命周期,或性能优化才会被写为功能组件

null

下面是一个可能会经常写的组件,评论列表组件,数据交互和展示都放到了一个组件里面。

// CommentList.js

class CommentList extends React.Component {

constructor() {

super();

this.state = { comments: [] }

}

componentDidMount() {

$.ajax({

url: "/my-comments.json",

dataType: 'json',

success: function(comments) {

this.setState({comments: comments});

}.bind(this)

});

}

render() {

return

  • {this.state.comments.map(renderComment)}
;

}

renderComment({body, author}) {

return

{body}—{author};

}

}

我们对上面的组件进行拆分,把他拆分成容器组件 CommentListContainer.js 和展示组件 CommentList。

// CommentListContainer.js

class CommentListContainer extends React.Component {

constructor() {

super();

this.state = { comments: [] }

}

componentDidMount() {

$.ajax({

url: "/my-comments.json",

dataType: 'json',

success: function(comments) {

this.setState({comments: comments});

}.bind(this)

});

}

render() {

return ;

}

}

// CommentList.js

class CommentList extends React.Component {

constructor(props) {

super(props);

}

render() {

return

  • {this.props.comments.map(renderComment)}
;

}

renderComment({body, author}) {

return

{body}—{author};

}

}

优势:

展示和容器更好的分离,更好的理解应用程序和UI

重用性高,展示组件可以用于多个不同的state数据源

展示组件就是你的调色板,可以把他们放到单独的页面,在不影响应用程序的情况下,让设计师调整UI

迫使你分离标签,达到更高的可用性

有状态组件和无状态组件

下面是一个最简单的无状态组件的例子:

function HelloComponent(props, /* context */) {

return

Hello {props.name}

}

ReactDOM.render(, mountNode)

可以看到,原本需要写“类”定义(React.createClass 或者 class YourComponent extends React.Component)来创建自己组件的定义(有状态组件),现在被精简成了只写一个 render 函数。更值得一提的是,由于仅仅是一个无状态函数,React 在渲染的时候也省掉了将“组件类” 实例化的过程。

结合 ES6 的解构赋值,可以让代码更精简。例如下面这个 Input 组件:

function Input({ label, name, value, ...props }, { defaultTheme }) {

const { theme, autoFocus, ...rootProps } = props

return (

htmlFor={name}

children={label || defaultLabel}

{...rootProps}

>

name={name}

type="text"

value={value || ''}

theme={theme || defaultTheme}

{...props}

/>

)}

Input.contextTypes = {defaultTheme: React.PropTypes.object};

无状态组件不像上述两种方法在调用时会创建新实例,它创建时始终保持了一个实例,避免了不必要的检查和内存分配,做到了内部优化。

无状态组件不支持 "ref"

高阶组件

高阶组件通过函数和闭包,改变已有组件的行为,本质上就是 Decorator 模式在 React 的一种实现。

当写着写着无状态组件的时候,有一天忽然发现需要状态处理了,那么无需彻底返工:)

往往我们需要状态的时候,这个需求是可以重用的。

高阶组件加无状态组件,则大大增强了整个代码的可测试性和可维护性。同时不断“诱使”我们写出组合性更好的代码。

高阶函数

function welcome() {

let username = localStorage.getItem('username');

console.log('welcome ' + username);

}

function goodbey() {

let username = localStorage.getItem('username');

console.log('goodbey ' + username);

}

welcome();

goodbey();

我们发现两个函数有一句代码是一样的,这叫冗余唉。(平时可能会有一大段代码的冗余)。

下面我们要写一个中间函数,读取username,他来负责把username传递给两个函数。

function welcome(username) {

console.log('welcome ' + username);

}

function goodbey(username) {

console.log('goodbey ' + username);

}

function wrapWithUsername(wrappedFunc) {

let newFunc = () => {

let username = localStorage.getItem('username');

wrappedFunc(username);

};

return newFunc;

}

welcome = wrapWithUsername(welcome);

goodbey = wrapWithUsername(goodbey);

welcome();

goodbey();

好了,我们里面的 wrapWithUsername 函数就是一个“高阶函数”。

他做了什么?他帮我们处理了 username,传递给目标函数。我们调用最终的函数 welcome的时候,根本不用关心 username是怎么来的。

举一反三的高阶组件

下面是两个冗余的组件。

import React, {Component} from 'react'

class Welcome extends Component {

constructor(props) {

super(props);

this.state = {

username: ''

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值