React专题—组件分割与解耦

1,082 阅读1分钟

1、分割 render 函数

示例1:

class Panel extends React.Component {
  renderHeading() {
    // ...
  }
  renderBody() {
    // ...
  }
  render() {
    return (
      <div>
        {this.renderHeading()}
        {this.renderBody()}
        </div>
    );
    }
}

示例2:

const PanelHeader = (props) => (
  // ...
);
const PanelBody = (props) => (
  // ...
);
class Panel extends React.Component {
  render() {
    return (
      <div>
        <PanelHeader title={this.props.title}/>
        <PanelBody content={this.props.content}/>
      </div>
    );
    }
}

2、用 props 传递元素

示例:

// 子组件
class CommentTemplate extends React.Component {
  static propTypes = {
    metadata: PropTypes.node,
    actions: PropTypes.node,
  };
  render() {
    return (
      <div>
        <CommentHeading>
          <Avatar user={...}/>
          <span>{this.props.metadata}</span>
            </CommentHeading>
            <CommentBody/>
        <CommentFooter>
          <Timestamp time={...}/>
          <span>{this.props.actions}</span>
            </CommentFooter>
        </div>
    );
    }
}

// 父组件
class Comment extends React.Component {
  render() {
    const metadata = this.props.publishTime ? <PublishTime time={this.props.publishTime} /> : <span>Saving...</span>;
    const actions = [];
    if (this.props.isSignedIn) {
      actions.push(<LikeAction />);
      actions.push(<ReplyAction />);
    }
    if (this.props.isAuthor) {
      actions.push(<DeleteAction />);
    }
    return <CommentTemplate metadata={metadata} actions={actions} />;
  }
}

3、使用高阶组件

示例:

// 高阶组件
const withLinkAnalytics = (mapPropsToData, WrappedComponent) => {
 class LinkAnalyticsWrapper extends React.Component {
   componentDidMount() {
     ReactDOM.findDOMNode(this).addEventListener('click', this.onClick);
   }
   componentWillUnmount() {
     ReactDOM.findDOMNode(this).removeEventListener('click', this.onClick);
   }
   onClick = (e) => {
     if (e.target.tagName === 'A') {
       const data = mapPropsToData ? mapPropsToData(this.props) : {};
       sendAnalytics('link clicked', data);
     }
   };
   render() {
     return <WrappedComponent {...this.props} />;
   }
 }
 return LinkAnalyticsWrapper;
};

// 普通组件
class Document extends React.Component {
 componentDidMount() {
   ReactDOM.findDOMNode(this).addEventListener('click', this.onClick);
 }
 componentWillUnmount() {
   ReactDOM.findDOMNode(this).removeEventListener('click', this.onClick);
 }
 onClick = (e) => {
   if (e.target.tagName === 'A') { 
     sendAnalytics('link clicked', {
       documentId: this.props.documentId
     });
   }
 };
 render() {
   // ...
 }
}

// 使用高阶组件
export default withLinkAnalytics((props) => ({
 documentId: props.documentId
}), Document);

4、巧妙利用children()传值

示例:

// Query.js
export default class QueryRenderer extends Component {
 // .......
 render() {
   const { data, children } = this.props;
   return children ? children(data) : null;
 }
}

// 使用
import Query from './Query.js';
<Query name="listMetrics" fetch={this.listMetrics} params={{ productId }}>
   {({ data }) => {
     // ......
     return (
       <MyComponent data={data} />
     );
   }}
</Query>