[譯]React 組件解耦之道
React 的組件非常的 靈活可擴展 ,不過隨著業務復雜度的增加和許多外部工具庫的引入,組件往往也會顯得 浮腫 ,接下來我們就一起來看看常見的幾種,遵循 單一職責原則 的,組件 分割與解耦 的方法
分割 render 函數
當一個組件渲染的內容較多時,有一個快速并且通用的方法是創建 sub-render 函數來簡化原來龐大的 render
class Panel extends React.Component {
renderHeading() {
// ...
}
renderBody() {
// ...
}
render() {
return (
<div>
{this.renderHeading()}
{this.renderBody()}
</div>
);
}
}
為了再次簡化 sub-render 函數,我們還可以采用 Functional Components 寫法,這種方式生成了更小的處理單元,且更有利于測試
const PanelHeader = (props) => (
// ...
);
const PanelBody = (props) => (
// ...
);
class Panel extends React.Component {
render() {
return (
<div>
// Nice and explicit about which props are used
<PanelHeader title={this.props.title}/>
<PanelBody content={this.props.content}/>
</div>
);
}
}
用 props 傳遞元素
如果一個組件的狀態或配置較多,我們可以運用 props 傳遞元素而不僅是數據,比如再聲明一個組件,使其中的父組件 只專注于配置
class CommentTemplate extends React.Component {
static propTypes = {
// Declare slots as type node
metadata: PropTypes.node,
actions: PropTypes.node,
};
render() {
return (
<div>
<CommentHeading>
<Avatar user={...}/>
// Slot for metadata
<span>{this.props.metadata}</span>
</CommentHeading>
<CommentBody/>
<CommentFooter>
<Timestamp time={...}/>
// Slot for actions
<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} />;
}
}
使用高階組件
實現點擊某組件的超鏈接,發送該組件的 ID,我們大多的解決方法可能如下
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') { // Naive check for <a> elements
sendAnalytics('link clicked', {
documentId: this.props.documentId // Specific information to be sent
});
}
};
render() {
// ...
}
}
然而它卻存在 代碼不能復用 , 組件重構困難 等問題
我們可以使用 高階組件 來解決這些問題,顧名思義,高階組件就是一個函數,傳給它一個組件,它返回一個新的組件
function 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') { // Naive check for <a> elements
const data = mapPropsToData ? mapPropsToData(this.props) : {};
sendAnalytics('link clicked', data);
}
};
render() {
// Simply render the WrappedComponent with all props
return <WrappedComponent {...this.props} />;
}
}
return LinkAnalyticsWrapper;
}
簡化代碼如下
class Document extends React.Component {
render() {
// ...
}
}
export default withLinkAnalytics((props) => ({
documentId: props.documentId
}), Document);
總結
以上 3 個 React 組件的 解耦重構 方法都可以直接拿來運用,最開始可能會覺得有點棘手,但是沒關系,只要堅持下來,你就會寫出更強大和可復用的代碼
來自:https://segmentfault.com/a/1190000010051000
本文由用戶 gl8661 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!