React实践小总结

142 阅读2分钟

给组件设置default props

class MyComponent extends React.Component{
  static defaultProps = {
    name: '',
    type: '',
    onClick: () => {}
  }

  handleClick = (e) => {
    this.props.onClick('handle click');
  };
  render() {
    return (
      <div onClick={this.handleClick}></div>
    )
  }
}
  • 在组件class的最顶部显示声明组件需要的属性,并赋值期望数据类型的默认值,例如name: '',表示name属性,期望的值是string类型,提升了代码的可读性。
  • 当组件收到父组件通过props传递过来的相应的属性值,传递过来的属性值会覆盖props上默认的属性值。
  • 不用去检查props上的某个属性是否存在,例如,this.props.onClick && this.props.onClick()这种语句。因为onClick已经在props上声明。

使用propTypes检查props上的属性值

class MyComponent extends React.Component{
  static defaultProps = {
    name: ''
  }

  static propTypes = {
    name: React.PropTypes.string.isRequired
    //其他的属性检查
  }

  render() {
    return (
      <div>{this.props.name}</div>
    )
  }
}
  • 当给组件传递的属性没有通过propTypes检查时,会报类似Warning: Failed prop type: Invalid prop typeof typenumbersupplied toExchangeDom, expected string.这样的错误。可以在开发阶段就及早发现错误。

组件内的方法应该只包含声明周期方法事件处理函数,以及可能会给其他组件调用的更新DOM的方法

//GOOD
class MyComponent extends React.Component{
  //构造函数
  constructor() {
    super();
  }

  //生命周期方法
  componentDidMount() {}
  componentWillReceiveProps() {}
  componentWillUpdate() {}
  componentDidUpdate() {}

  //事件处理函数
  handleClick = () => {}
  /*handleChange = () => {}*/
  /*handleMouseOver = () => {}*/
  /*handleFocus = () => {}*/

  //点击tab,页面滚动到相应的锚点
  handleTabClick = (key, label) => {
    const el = document.getElementById(tabKey);
    const alignToTop = true;

    //可以,但更好的方式是封装该方法,可以使该方法复用
    //el.scrollIntoView(alignToTop);

    //封装后的方法
    DOM.scrollIntoView(el, alignToTop);

  }

  updateSomeView(value) {
    DOM.someOperate(value);
    // or
    this.setState({value});
  }

  render() {
    return (
      <div>
        <button type='button' onClick={this.handleClick}></button>
        <Tabs>
          {
            [...helper.tabMap.keys()].map((tabKey, idx) => {
              const label = helper.tabMap.get(tabKey);
              return <Tab key={tabKey} label={label} onClick={() => this.handleTabClick(tabKey, label)} active={tabKey === this.type}/>
            })
          }
        </Tabs>
      </div>
    )
  }
}

class Root extends React.Component{
  componentDidMount() {
    if(someCondidtion) {
      const someValue = someCaculate();
      this._myComponentInstance.updateSomeView(someValue);
    }
  }
  render() {
    return (
      <MyComponent ref={ref => this._myComponentInstance = ref;}/>
    )
  }
}
  • 通过es6 class定义的组件或者React.createClass({...})定义的组件,除constructorrendergetDefaultPropsgetInitialState这几个方法外,应该只包含处理组件自身视图的生命周期方法事件处理函数,以及可能会给其他组件调用的方法,例如更新DOM的方法, 参考updateSomeView方法。
  • 生命周期方法事件处理函数以及供其他组件调用的更新视图的方法中可以包含DOM的操作。例如,根据点击的tabkey跳转到页面的不同锚点,参考handleTabClick
  • React是视图(view层),其视图由组件构造,视图中就应该包含视图逻辑,视图(DOM)操作,视图的事件处理函数,业务逻辑应该放在reduxreducer中(model层)。
  • 下面来看个实际项目中组件内包含过多不应该出现在组件中的方法的例子:
//BAD
class MyComponent extends React.Component{

  //排序方法
  mpInfosSortRule(a, b) {
    let aStore = a.store;
    let bStore = b.store;
    let aFrontDisabled = aStore.frontDisabled || 0;
    let bFrontDisabled = bStore.frontDisabled || 0;
    return aFrontDisabled - bFrontDisabled;
	}

  //格式化方法
  dateFormat() {}
  currencyFormat() {}

  //各种工具方法

  render() {
    const {o2oMpInfos} = this.props;

    o2oMpInfos.sort(this.mpInfosSortRule);

    return (
      <div>
        {/*do some render work with o2oMpInfos*/}
      </div>
    )
  }
}

这些抽象的方法,可以根据功能划分到util工具方法中。
以上就是我在实际使用react中的一些小总结。