首页 > 其他分享 >React中重用代码的技术

React中重用代码的技术

时间:2023-02-27 17:55:29浏览次数:27  
标签:return HOC render 代码 重用 React props 组件

1. Render Prop

具有 render prop 的组件接受一个返回 React元素的函数,并在组件内部通过调用此函数来
实现自己的渲染逻辑, 具体来说render prop 是一个用于告知组件需要渲染什么内容的函数 prop。

<DataProvider render={data => (
  <h1>Hello {data.target}</h1>
)}/>

在Mouse组件中利用render prop模式渲染Cat组件,从而实现对Mouse组件的复用

class Cat extends React.Component {
  render() {
    const mouse = this.props.mouse;
    return (
      <img src="/cat.jpg" style={{ position: 'absolute', left: mouse.x, top: mouse.y }} />
    );
  }
}

class Mouse extends React.Component {
  constructor(props) {
    super(props);
    this.handleMouseMove = this.handleMouseMove.bind(this);
    this.state = { x: 0, y: 0 };
  }

  handleMouseMove(event) {
    this.setState({
      x: event.clientX,
      y: event.clientY
    });
  }

  render() {
    return (
      <div style={{ height: '100vh' }} onm ouseMove={this.handleMouseMove}>

        {/*
          使用 `render`prop 动态决定要渲染的内容,
          而不是给出一个 <Mouse> 渲染结果的静态表示
        */}
        {this.props.render(this.state)}
      </div>
    );
  }
}

class MouseTracker extends React.Component {
  render() {
    return (
      <div>
        <h1>移动鼠标!</h1>
        <Mouse render={mouse => (
          <Cat mouse={mouse} />
        )}/>
      </div>
    );
  }
}

注意:render prop 是因为模式才被称为 render prop ,你不一定要用名为 render 的 prop 来使用这种模式。
任何被用于告知组件需要渲染什么内容的函数 prop 在技术上都可以被称为 “render prop”。

<Mouse children={mouse => (
  <p>鼠标的位置是 {mouse.x},{mouse.y}</p>
)}/>

2. 高阶组件(HOC)

高阶组件(HOC)是 React 中用于复用组件逻辑的一种高级技巧, 它是一种基于 React 的组合特性而形成的设计模式。 具体而言,高阶组件是参数为组件,返回值为新组件的函数。

const EnhancedComponent = higherOrderComponent(WrappedComponent);

HOC 不应该修改传入组件,而应该使用组合的方式,通过将组件包装在容器组件中实现功能,
HOC 与容器组件模式之间有相似之处。容器组件担任将高级和低级关注点分离的责任,
由容器管理订阅和状态,并将 prop 传递给处理 UI 的组件。HOC 使用容器作为其实现的一部分,
你可以将 HOC 视为参数化容器组件。

function logProps(WrappedComponent) {
  return class extends React.Component {
    componentDidUpdate(prevProps) {
      console.log('Current props: ', this.props);
      console.log('Previous props: ', prevProps);
    }
    render() {
      // 将 input 组件包装在容器中,而不对其进行修改。Good!
      return <WrappedComponent {...this.props} />;
    }
  }
}
// 此函数接收一个组件...
function withSubscription(WrappedComponent, selectData) {
  // ...并返回另一个组件...
  return class extends React.Component {
    constructor(props) {
      super(props);
      this.handleChange = this.handleChange.bind(this);
      this.state = {
        data: selectData(DataSource, props)
      };
    }

    componentDidMount() {
      // ...负责订阅相关的操作...
      DataSource.addChangeListener(this.handleChange);
    }

    componentWillUnmount() {
      DataSource.removeChangeListener(this.handleChange);
    }

    handleChange() {
      this.setState({
        data: selectData(DataSource, this.props)
      });
    }

    render() {
      // ... 并使用新数据渲染被包装的组件!
      // 请注意,我们可能还会传递其他属性
      return <WrappedComponent data={this.state.data} {...this.props} />;
    }
  };
}

const CommentListWithSubscription = withSubscription(
  CommentList,
  (DataSource) => DataSource.getComments()
);

const BlogPostWithSubscription = withSubscription(
  BlogPost,
  (DataSource, props) => DataSource.getBlogPost(props.id)
);
  • 约定将不相关的 props 传递给被包裹的组件
    HOC 为组件添加特性。自身不应该大幅改变约定。HOC 返回的组件与原组件应保持类似的接口。
    HOC 应该透传与自身无关的 props。大多数 HOC 都应该包含一个类似于下面的 render 方法,
    这种约定保证了 HOC 的灵活性以及可复用性。
render() {
  // 过滤掉非此 HOC 额外的 props,且不要进行透传
  const { extraProp, ...passThroughProps } = this.props;

  // 将 props 注入到被包装的组件中。
  // 通常为 state 的值或者实例方法。
  const injectedProp = someStateOrInstanceMethod;

  // 将 props 传递给被包装组件
  return (
    <WrappedComponent
      injectedProp={injectedProp}
      {...passThroughProps}
    />
  );
}
  • 使用HOC注意事项
    不要在 render 方法中使用 HOC
render() {
  // 每次调用 render 函数都会创建一个新的 EnhancedComponent
  // EnhancedComponent1 !== EnhancedComponent2
  const EnhancedComponent = enhance(MyComponent);
  // 这将导致子树每次渲染都会进行卸载,和重新挂载的操作!
  return <EnhancedComponent />;
}

务必复制静态方法

function enhance(WrappedComponent) {
  class Enhance extends React.Component {/*...*/}
  // 必须准确知道应该拷贝哪些方法 :(
  Enhance.staticMethod = WrappedComponent.staticMethod;
  return Enhance;
}

Refs 不会被传递
虽然高阶组件的约定是将所有 props 传递给被包装组件,但这对于 refs 并不适用。那是因为 ref 实际上并不是一个 prop - 就像 key 一样,它是由 React 专门处理的。如果将 ref 添加到 HOC 的返回组件中,则 ref 引用指向容器组件,而不是被包装组件。可以通过使用 React.forwardRef来
解决此类问题。

3. 使用自定义Hook

将多个组件中共有的功能特性和state抽取在一个函数中

import { useState, useEffect } from 'react';

function useFriendStatus(friendID) {
  const [isOnline, setIsOnline] = useState(null);

  useEffect(() => {
    function handleStatusChange(status) {
      setIsOnline(status.isOnline);
    }

    ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);
    };
  });

  return isOnline;
}

function FriendStatus(props) {
  const isOnline = useFriendStatus(props.friend.id);

  if (isOnline === null) {
    return 'Loading...';
  }
  return isOnline ? 'Online' : 'Offline';
}

function FriendListItem(props) {
  const isOnline = useFriendStatus(props.friend.id);

  return (
    <li style={{ color: isOnline ? 'green' : 'black' }}>
      {props.friend.name}
    </li>
  );

标签:return,HOC,render,代码,重用,React,props,组件
From: https://www.cnblogs.com/xiaodi-js/p/17161306.html

相关文章