ReactNative重用高阶组件、render props和H

2021-01-26  本文已影响0人  iOS小童

ReactNative重用高阶组件、render props和Hook

在日积月累的需求下,不同开发人员导致重复代码越来越多,解决重用安排上日程,在不同需求和不同场景下选择不同的方式显然难能可贵,当然要全部了解并能熟练使用才能更好地选择,以下只介绍如何重用组件和组件外部事件,其他功能需自我探索,react官网了解并学习最新实践

高阶组件

什么是高阶组件?

  1. 高阶组件(HOC)是 React 中用于复用组件逻辑的一种高级技巧。HOC 自身不是 React API 的一部分,它是一种基于 React 的组合特性而形成的设计模式
# 本身是一个函数,接受一个组件作为参数,返回一个组件的函数

function withSubscription(WrappedComponent) {
    return class abc extends React.Component {
        render() {
            return (
                <WrappedComponent {...this.props} />
            )
        }
    }

}
export default withSubscription;

举个例子:

  1. BlogPost一个用于订阅单个博客帖子的组件
  2. CommentList它订阅外部数据源,用以渲染评论列表
    CommentList 和 BlogPost 不同 - 它们在 DataSource 上调用不同的方法,且渲染不同的结果。但它们的大部分实现都是一样的:
// 此函数接收一个组件...
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 外部数据源
      DataSource.addChangeListener(this.handleChange);
    }

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

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

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

Hook

Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。

那么什么是hook?

  1. Hook 是一些可以让你在函数组件里“钩入” React state 及生命周期等特性的函数
  2. 可以创建不同的 Hook 来复用不同组件之间的状态逻辑
  3. 在 React 的函数组件中调用 Hook
  4. 不要在循环,条件或嵌套函数中调用 Hook
import React, { useState } from 'react';

function Example() {
  // 声明一个叫 “count” 的 state 变量。
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

hook如何复用?

当我们想在两个函数之间共享逻辑时,我们会把它提取到第三个函数中。而组件和 Hook 都是函数,所以也同样适用这种方式。
举个例子:订阅某个好友的在线状态。

# useFriendStatus 的 Hook 目的是订阅某个好友的在线状态。
# 这就是我们需要将 friendID 作为参数,并返回这位好友的在线状态的原因。

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;
}

# FriendStatus使用useFriendStatus

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

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

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

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

render props

render props是什么?

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

render props 如何复用?

举个例子:

假设我们有一个 <Cat> 组件,它可以呈现一张在屏幕上追逐鼠标的猫的图片。
我们或许会使用 <Cat mouse={{ x, y }} prop 来告诉组件鼠标的坐标以让它知道图片应该在屏幕哪个位置。
<Mouse> 组件封装了所有关于监听 mousemove 事件和存储鼠标 (x, y) 位置的行为,

// <Mouse> 组件封装了我们需要的行为...
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' }} onMouseMove={this.handleMouseMove}>

        {/*
          Instead of providing a static representation of what <Mouse> renders,
          use the `render` prop to dynamically determine what to render.
        */}
        {this.props.render(this.state)}
      </div>
    );
  }
}

# <Cat> 组件,它可以呈现一张在屏幕上追逐鼠标的猫的图片

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 }} />
    );
  }
}

# 我们提供了一个 render 方法 让 <Mouse> 能够动态决定什么需要渲染,
# 而不是克隆 <Mouse> 组件然后硬编码来解决特定的用例

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

猜你喜欢

热点阅读