React 中渲染 Props 的概述

Avatar of Kingsley Silas
Kingsley Silas

DigitalOcean 为您旅程的每个阶段提供云产品。立即开始使用 200 美元的免费额度!

React 中渲染 Props 的概述

在 React 中使用渲染 Props 是一种有效重用代码的技术。根据 React 文档,“具有渲染 Props 的组件接受一个返回 React 元素的函数,并调用它而不是实现自己的渲染逻辑。” 为了理解这意味着什么,让我们看一下渲染 Props 模式,然后将其应用于几个简单的示例。

渲染 Props 模式

在使用渲染 Props 时,您将一个渲染函数传递给一个组件,该组件依次返回一个 React 元素。此渲染函数由另一个组件定义,接收组件共享通过渲染函数传递的内容。

这就是它的样子

class BaseComponent extends Component {
  render() {
    return <Fragment>{this.props.render()}</Fragment>;
  }
}

假设我们的 App 是一个礼品盒,其中 App 本身是顶部的蝴蝶结。如果盒子是我们正在创建的组件,我们打开它,我们将公开使组件在 render() 调用后工作所需的 props、状态、函数和方法。

组件的渲染函数通常包含形成该组件 DOM 的所有 JSX 等。相反,此组件具有一个渲染函数 this.props.render(),该函数将显示通过 props 传入的组件。

示例:创建计数器

查看 Kingsley Silas Chijioke (@kinsomicrote) 在 CodePen 上的笔 React 渲染 Props

让我们做一个简单的计数器示例,根据单击的按钮增加或减少值。

首先,我们从创建一个将用于包装初始状态、方法和渲染的组件开始。有创意地,我们将此称为 Wrapper

class Wrapper extends Component {
  state = {
    count: 0
  };

  // Increase count
  increment = () => {
    const { count } = this.state;
    return this.setState({ count: count + 1 });
  };

  // Decrease count
  decrement = () => {
    const { count } = this.state;
    return this.setState({ count: count - 1 });
  };

  render() {
    const { count } = this.state;

    return (
      <div>
        {this.props.render({
          increment: this.increment,
          decrement: this.decrement,
          count: count
        })}
      </div>
    );
  }
}

Wrapper 组件中,我们指定方法和状态,这些方法和状态会暴露给包装的组件。对于此示例,我们需要 incrementdecrement 方法。我们的默认 count 设置为 0。逻辑是根据触发的函数增加或减少 count,从零值开始。

如果您查看 return() 方法,您会看到我们正在使用 this.props.render()。正是通过此函数,我们从 Wrapper 组件传递方法和状态,以便被其包装的组件将使用它。

要将其用于我们的 App 组件,该组件将如下所示

class App extends React.Component {
  render() {
    return (
      <Wrapper
        render={({ increment, decrement, count }) => (
          <div>
            <div>
              <h3>Render Props Counter</h3>
            </div>
            <div>
              <p>{count}</p>
              <button onClick={() => increment()}>Increment</button>
              <button onClick={() => decrement()}>Decrement</button>
            </div>
          </div>
        )}
      />
    );
  }
}

示例:创建数据列表

收益在于渲染 Props 的可重用能力,让我们创建一个可以用于处理从 API 获取的数据列表的组件。

查看 Kingsley Silas Chijioke (@kinsomicrote) 在 CodePen 上的笔 React 渲染 Props 2

这次我们想要从包装器组件中得到什么?我们希望将我们想要渲染的数据的源链接传递给它,然后发出 GET 请求以获取数据。获取数据后,我们将其设置为组件的新状态并进行渲染以显示。

class Wrapper extends React.Component {
  state = {
    isLoading: true,
    error: null,
    list: []
  };

  fetchData() {
    axios.get(this.props.link)
      .then((response) => {
        this.setState({
          list: response.data,
          isLoading: false
        });
    })
    .catch(error => this.setState({ error, isLoading: false }));
  }

  componentDidMount() {
    this.setState({ isLoading: true }, this.fetchData);
  }

  render() {
    return this.props.render(this.state);
  }
}

数据链接将作为 props 传递给 Wrapper 组件。当我们从服务器获取响应时,我们使用从服务器返回的内容更新 list。组件挂载后会向服务器发出请求。

以下是 Wrapper 的使用方法

class App extends React.Component {
  render() {
    return (
      <Wrapper
        link="https://jsonplaceholder.typicode.com/users"
        render={({ list, isLoading, error }) => (
          <div>
            <h2>Random Users</h2>
            {error ? <p>{error.message}</p> : null}
            {isLoading ? (
              <h2>Loading...</h2>
            ) : (
              <ul>{list.map(user => <li key={user.id}>{user.name}</li>)}</ul>
            )}
          </div>
        )}
      />
    );
  }
}

您可以看到我们传递链接作为 prop,然后我们使用 ES6 解构来获取 Wrapper 组件的状态,然后将其渲染。组件首次加载时,我们显示加载文本,一旦我们从服务器获取响应和数据,就会将其替换为项目列表。

此处的 App 组件是一个类组件,因为它不管理状态。我们可以将其转换为函数式无状态组件。

const App = () => {
  return (
    <Wrapper
      link="https://jsonplaceholder.typicode.com/users"
      render={({ list, isLoading, error }) => (
        <div>
          <h2>Random Users</h2>
          {error ? <p>{error.message}</p> : null}
          {isLoading ? (
            <h2>Loading...</h2>
          ) : (
            <ul>{list.map(user => <li key={user.id}>{user.name}</li>)}</ul>
          )}
        </div>
      )}
    />
  );
}

总结!

人们经常将渲染 Props 与 高阶组件 进行比较。如果您想走这条路,我建议您也 查看这篇文章 以及 Michael Jackson 关于此主题的 这篇有见地的演讲