React形式【译】

原文:react-patterns

代码构造

  • class definition

    • constructor

      • event handlers

    • ‘component’ lifecycle

    • getters

    • render

  • defaultProps

  • proptypes

class Person extends React.Component {
  constructor (props) {
    super(props);

    this.state = { smiling: false };

    this.handleClick = () => {
      this.setState({smiling: !this.state.smiling});
    };
  }

  componentWillMount () {
    // add event listeners (Flux Store, WebSocket, document, etc.)
  },

  componentDidMount () {
    // React.getDOMNode()
  },

  componentWillUnmount () {
    // remove event listeners (Flux Store, WebSocket, document, etc.)
  },

  get smilingMessage () {
    return (this.state.smiling) ? "is smiling" : "";
  }

  render () {
    return (
      <div onClick={this.handleClick}>
        {this.props.name} {this.smilingMessage}
      </div>
    );
  },
}

Person.defaultProps = {
  name: 'Guest'
};

Person.propTypes = {
  name: React.PropTypes.string
};

格式化属性

当有2个以上属性时,就换行显现

// bad
<Person
 firstName="Michael" />

// good
<Person firstName="Michael" />
// bad
<Person firstName="Michael" lastName="Chan" occupation="Designer" favoriteFood="Drunken Noodles" />

// good
<Person
 firstName="Michael"
 lastName="Chan"
 occupation="Designer"
 favoriteFood="Drunken Noodles" />

依靠属性

运用getters要领替换定义依靠属性

// bad
  firstAndLastName () {
    return `${this.props.firstName} ${this.props.lastname}`;
  }

  // good
  get fullName () {
    return `${this.props.firstName} ${this.props.lastname}`;
  }

依靠状况

运用getters要领替换定义依靠状况,注重为了进步可读性须要在定名时加上一个动词前缀。

// bad
happyAndKnowsIt () {
  return this.state.happy && this.state.knowsIt;
}
// good
get isHappyAndKnowsIt () {
  return this.state.happy && this.state.knowsIt;
}

这些要领必需返回boolean范例

用三元运算替换Sub-render要领

保证衬着逻辑都写在render要领里

// bad
renderSmilingStatement () {
  return <strong>{(this.state.isSmiling) ? " is smiling." : ""}</strong>;
},

render () {
  return <div>{this.props.name}{this.renderSmilingStatement()}</div>;
}
// good
render () {
  return (
    <div>
      {this.props.name}
      {(this.state.smiling)
        ? <span>is smiling</span>
        : null
      }
    </div>
  );
}

视图组件

用定义的组件构成视图。不要建立混杂着规划和功用的一次性组件

// bad
class PeopleWrappedInBSRow extends React.Component {
  render () {
    return (
      <div className="row">
        <People people={this.state.people} />
      </div>
    );
  }
}
// good
class BSRow extends React.Component {
  render () {
    return <div className="row">{this.props.children}</div>;
  }
}

class SomeView extends React.Component {
  render () {
    return (
      <BSRow>
        <People people={this.state.people} />
      </BSRow>
    );
  }
}

容器组件(有状况组件)

容器组件担任猎取数据并交付给相应的子组件衬着,仅此而已。— Jason Bonta

// bad
// CommentList.js

class CommentList extends React.Component {
  getInitialState () {
    return { comments: [] };
  }

  componentDidMount () {
    $.ajax({
      url: "/my-comments.json",
      dataType: 'json',
      success: function(comments) {
        this.setState({comments: comments});
      }.bind(this)
    });
  }

  render () {
    return (
      <ul>
        {this.state.comments.map(({body, author}) => {
          return <li>{body}—{author}</li>;
        })}
      </ul>
    );
  }
}
//good
// CommentList.js

class CommentList extends React.Component {
  render() {
    return (
      <ul>
        {this.props.comments.map(({body, author}) => {
          return <li>{body}—{author}</li>;
        })}
      </ul>
    );
  }
}
// CommentListContainer.js

class CommentListContainer extends React.Component {
  getInitialState () {
    return { comments: [] }
  }

  componentDidMount () {
    $.ajax({
      url: "/my-comments.json",
      dataType: 'json',
      success: function(comments) {
        this.setState({comments: comments});
      }.bind(this)
    });
  }

  render () {
    return <CommentList comments={this.state.comments} />;
  }
}

相干链接:
Container Components
React.js Conf 2015 – Making your app fast with high-performance components

render中缓存状况

不要在render中缓存状况

// bad
render () {
  let name = `Mrs. ${this.props.name}`;

  return <div>{name}</div>;
}

// good
render () {
  return <div>{`Mrs. ${this.props.name}`}</div>;
}
// best
get fancyName () {
  return `Mrs. ${this.props.name}`;
}

render () {
  return <div>{this.fancyName}</div>;
}

这里多半是出于代码作风的斟酌,不过照样坚持比较好,我疑心也能够跟机能有关。

复合前提

不要把复合前提推断放在render里。

// bad
render () {
  return <div>{if (this.state.happy && this.state.knowsIt) { return "Clapping hands" }</div>;
}
// better
get isTotesHappy() {
  return this.state.happy && this.state.knowsIt;
},

render() {
  return <div>{(this.isTotesHappy) && "Clapping hands"}</div>;
}

这里最好的解决方案是运用容器组件来治理你的状况然后在经由过程属性(props)往基层通报。

搜检空值

不要去搜检是不是存在某个prop值,快运用defaultProps

// bad
render () {
  if (this.props.person) {
    return <div>{this.props.person.firstName}</div>;
  } else {
    return null;
  }
}
// good
class MyComponent extends React.Component {
  render() {
    return <div>{this.props.person.firstName}</div>;
  }
}

MyComponent.defaultProps = {
  person: {
    firstName: 'Guest'
  }
};

当你的值是对象或许数组时,运用 PropTypes.shape声明嵌套数据的预期范例。

经由过程Props设置State

不要经由过程props值去设置state,除非显著是个初始值。

// bad
getInitialState () {
  return {
    items: this.props.items
  };
}
// good
getInitialState () {
  return {
    items: this.props.initialItems
  };
}

细致请浏览官网的Props in getInitialState Is an Anti-Pattern

定名事宜相应要领

// bad
punchABadger () { /*...*/ },

render () {
  return <div onClick={this.punchABadger} />;
}
// good
handleClick () { /*...*/ },

render () {
  return <div onClick={this.handleClick} />;
}

处置惩罚要领的定名必需:

  • 第一个单词为handle

  • 末了一个单词为要相应的事宜(比方Click,Change)

  • 如今时态
    假如为了防止定名争执,你能够在handle和事宜名中心到场其他信息。比方,你能够定义handleNameChange 和handleAgeChange来辨别onChange的差别相应处置惩罚。不过当你如许做的时刻,你要问问本身是不是须要一个新的组件了。

定名事宜

能够运用自定义事宜替换预设的事宜名。

class Owner extends React.Component {
  handleDelete () {
    // handle Ownee's onDelete event
  }

  render () {
    return <Ownee onDelete={this.handleDelete} />;
  }
}

class Ownee extends React.Component {
  render () {
    return <div onChange={this.props.onDelete} />;
  }
}

Ownee.propTypes = {
  onDelete: React.PropTypes.func.isRequired
};

运用PropTypes

运用PropTypes能够预先定义属性的范例,能够在以后取得一些有意义的正告信息。

MyValidatedComponent.propTypes = {
  name: React.PropTypes.string
};

MyValidatedComponentname属性值假如不是string范例的话, 会输出正告。

<Person name=1337 />
// Warning: Invalid prop `name` of type `number` supplied to `MyValidatedComponent`, expected `string`.

在这里也能够设置属性是不是是必需存在的。

MyValidatedComponent.propTypes = {
  name: React.PropTypes.string.isRequired
}

这个组件会考证是不是存在name属性。

<Person />
// Warning: Required prop `name` was not specified in `Person`

相干链接:Prop Validation

运用特殊符号

要在运用React中运用特殊符号,请运用String.fromCharCode()

// bad
<div>PiCO · Mascot</div>

// nope
<div>PiCO &middot; Mascot</div>

// good
<div>{'PiCO ' + String.fromCharCode(183) + ' Mascot'}</div>

// better
<div>{`PiCO ${String.fromCharCode(183)} Mascot`}</div>

相干链接:HTML Entities

Tables

浏览器以为你是愚昧的,然则React不这么工资。请一直为你的table组件增加tbody。

// bad
render () {
  return (
    <table>
      <tr>...</tr>
    </table>
  );
}

// good
render () {
  return (
    <table>
      <tbody>
        <tr>...</tr>
      </tbody>
    </table>
  );
}

浏览器会自动插进去tbody当你忘了写它。React则不会,如许会给你的代码带来杂沓,请记着运用tbody。

classnames

运用classNames治理你的classes逻辑。

// bad
get classes () {
  let classes = ['MyComponent'];

  if (this.state.active) {
    classes.push('MyComponent--active');
  }

  return classes.join(' ');
}

render () {
  return <div className={this.classes} />;
}
// good
render () {
  let classes = {
    'MyComponent': true,
    'MyComponent--active': this.state.active
  };

  return <div className={classnames(classes)} />;
}

相干链接:Class Name Manipulation

    原文作者:华山D小黑
    原文地址: https://segmentfault.com/a/1190000006709474
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞