react使用高阶组件好处
by Adam Recvlohe
通过亚当·雷夫洛厄(Adam Recvlohe)
如何使用React的高阶组件 (How to use React’s higher-order components)
When React first hit the scene, it brought with it a new way of developing front-end architectures. It was regarded as the “View” in Model-View-Controller.
当React首次出现时,它带来了一种开发前端架构的新方法。 在Model-View-Controller中,它被视为“视图”。
Over time, core contributors to the React ecosystem have latched onto the container/presentational pattern.
随着时间的流逝,React生态系统的核心贡献者已经锁定在容器/表示模式上。
In this post, you’ll learn more about the container/presentational pattern and how you can use it to create React components.
在本文中,您将了解有关容器/表示模式的更多信息,以及如何使用它来创建React组件。
Before I go any further, let’s clarify some of the jargon:
在进一步介绍之前,让我们澄清一些术语:
- A container is a component that fetches and/or transforms data. 容器是获取和/或转换数据的组件。
- A presentational component presents/displays the data it’s passed through its props. Nothing else. 演示组件显示/显示通过道具传递的数据。 没有其他的。
- A container acts as a higher-order component. Composing higher-order components together allows you to separate those two layers. This prevents you from mudding your presentational layer with unnecessary logic. 容器充当高阶组件。 将高阶组件组合在一起可以使您将这两层分开。 这样可以防止您用不必要的逻辑混淆表示层。
If you want, you can follow along using ESNextbin.
如果需要,可以使用ESNextbin。
After navigating to that page, at the top you should see three tabs: CODE, HTML, and PACKAGE. Click on PACKAGE. After navigating to that tab add react and react-dom as dependencies.
导航到该页面后,您应该在顶部看到三个标签: CODE , HTML和PACKAGE 。 点击包装 。 导航到该选项卡后,添加react和react-dom作为依赖项 。
{ “name”: “esnextbin-sketch”, “version”: “0.0.0”, “dependencies”: { “react” : “latest”, “react-dom”: “latest” }}
Now click on the CODE tab and then import react and render from react-dom.
现在单击CODE选项卡,然后从react-dom导入react和render 。
import { default as React } from ‘react’import { render } from ‘react-dom’
Now let’s create a stateless functional component that renders ‘Hello, world!’
现在,让我们创建一个呈现“ Hello,world!”的无状态功能组件。
const Presentational = () => <div>Hello, world!</div>
After, you just need to mount that component to the DOM using render.
之后,您只需要使用render将组件安装到DOM。
render(<Presentational />, document.querySelector(‘#root’))
You still haven’t created the root element in the HTML, so let’s do that now. All you are doing is adding a div with the id of root.
您还没有在HTML中创建根元素,所以现在就开始做吧。 您要做的只是添加一个ID为root的div 。
<!doctype html><html><head> <meta charset=”utf-8"> <title>ESNextbin Sketch</title> <! — put additional styles and scripts here →</head><body> // Notice something different <div id=‘root’></div></body></html>
Now for the moment of truth. Click EXECUTE in the top right corner of the page. You should see Hello, world! on the screen.
现在是关键时刻。 点击页面右上角的执行 。 您应该看到世界,您好! 屏幕上。
You now have a presentational component. But you also need a container component to fetch your data.
现在,您有了一个演示组件。 但是,您还需要一个容器组件来获取数据。
Let’s create a container component above the presentational one. To create the container you will be using React’s class component. For this reason, you will need to import it at the top of the page.
让我们在演示组件之上创建一个容器组件。 要创建容器,您将使用React的class组件。 因此,您需要在页面顶部将其导入。
import { default as React, Component } from ‘react’
At this point you can get busy with creating the container component.
此时,您可以忙于创建容器组件。
class Container extends Component { state = { data: [] } componentDidMount() { fetch(‘https://fcctop100.herokuapp.com/api/fccusers/top/alltime') .then(response => response.json()) .then(data => this.setState({ data })) } render() { return <Presentational data={this.state.data} /> }}
At the top, you have the state that is an empty array. You are using a lifecycle method called componentDidMount where you will fetch the data.
在顶部,状态为空数组。 您正在使用一种称为componentDidMount的生命周期方法,将从中获取数据。
When the response returns you then update the state with the data. The data is then passed as a prop to the presentational component. This means you will need to update your presentational component as well.
当响应返回时,您然后用数据更新状态。 然后将数据作为道具传递给表示组件。 这意味着您还需要更新演示组件。
const Presentational = ({ data }) => <div>{JSON.stringify(data)}</div>
Here I am using destructuring to pluck data off the props object. Otherwise it would look like this:
在这里,我正在使用解构从props对象中提取数据 。 否则它将如下所示:
const Presentational = props => <div>{JSON.stringify(props.data)}</div>
These changes force you to update which component gets mounted. You now need to render the container component.
这些更改迫使您更新要安装的组件。 现在,您需要渲染容器组件。
render(<Container />, document.querySelector(‘#root’))
When you click on EXECUTE you should see a hole heap of data overflowing on your screen. Oh my!
当您单击EXECUTE时,您应该在屏幕上看到大量的数据溢出。 天啊!
What you have done here is abstract away the container component and everything it does. But it’s not flexible. You have to place your presentational component inside the container. Is there another way of doing it that’s more flexible? Enter the higher-order component.
您在这里所做的就是抽象化容器组件及其所做的一切。 但这并不灵活。 您必须将演示组件放在容器中。 还有另一种更灵活的方法吗? 输入高阶分量。
A higher-order component is a function that takes a component and returns a new component. How would that look in practice. Let’s create a function that takes a component and returns a new component with the data from the FCC API. You will be updating the container component to do this.
高阶组件是接收组件并返回新组件的函数。 实际情况如何。 让我们创建一个函数,该函数接受一个组件并使用FCC API中的数据返回一个新组件。 您将更新容器组件以执行此操作。
const container = Presentational => class extends Component { state = { data: [] } componentDidMount() { fetch(‘https://fcctop100.herokuapp.com/api/fccusers/top/alltime') .then(response => response.json()) .then(data => this.setState({ data })) } render() { return <Presentational data={this.state.data} /> }}
Nothing too different here. There is, however, one extra step you have to perform. You need to compose this container and presentational component together. I am just calling container with the presentational component as an argument. This is added just below your presentational component.
这里没什么不同。 但是,您还需要执行一个额外的步骤。 您需要将这个容器和表示组件一起组成。 我只是用表示组件作为参数来调用容器。 这被添加到您的演示组件的正下方。
const HigherOrderComponent = container(Presentational)
Now all you have to do is render the higher-order component.
现在您所要做的就是渲染高阶组件。
render(<HigherOrderComponent />, document.querySelector(‘#root’))
You see what you did there? Now you can use the container with any component, not just the presentational component!
你看到你在那里做了什么吗? 现在,您可以将容器与任何组件一起使用,而不仅仅是演示组件!
Let’s take this one step further though. Let’s call another function that tells the container component what data to fetch. I think that would make the container even more flexible.
不过,让我们更进一步。 让我们调用另一个告诉容器组件要提取哪些数据的函数。 我认为这将使容器更加灵活。
The new container will look something like this:
新的容器将如下所示:
const container = endpoint => Presentational => class extends Component { state = { data: [] } componentDidMount() { fetch(endpoint) .then(response => response.json()) .then(data => this.setState({ data })) } render() { return <Presentational data={this.state.data} /> }}
Now you will need to update the higher-order component to handle the new call to the endpoint.
现在,您将需要更新高阶组件以处理对端点的新调用。
const HigherOrderComponent = container( ‘https://fcctop100.herokuapp.com/api/fccusers/top/alltime')(Presentational)
If that looks a little off to you then you have good eye. What if you could abstract that out even further? Enter recompose!
如果您觉得这有点不对劲,那么您的眼睛就很好。 如果您可以进一步将其抽象出来怎么办? 输入重组 !
Let’s pause for a moment now and cover what the idea of compose is. To understand compose you need to understand mapping.
现在让我们暂停片刻,介绍一下compose的概念。 要了解撰写,您需要了解映射。
Mapping in computer programming is when you take a value and transform it into another value. Which is basically every function ever created! Let me give you an example for good measure.
在计算机编程中进行映射是指获取一个值并将其转换为另一个值。 这基本上是有史以来创建的每个函数! 让我给你一个很好的例子。
function double(x) { return x * 2}
const doubled = double(2)
Now let’s say I want to make another transformation, for example triple. How would I do that?
现在假设我要进行另一个转换,例如三重转换。 我该怎么做?
function triple(x) { return x * 3 }
function double(x) { return x * 2}
const messedAroundAndGotATripleDouble = triple(double(2))
Simple enough, right? What if I wanted to make another transformation, and another, and another. It would get quite long. With the help of a compose function you can make the code not only more readable but more composable.
很简单,对不对? 如果我想进行另一个转换,另一个转换,该怎么办。 它会变得很长。 借助compose函数,您不仅可以使代码更具可读性,而且可以使组合性更高。
function compose(f, g) { return function(x) { return f(g(x)) }}
function triple(x) { return x * 3 }
function double(x) { return x * 2}
const tripleThenDouble = compose(triple, double)
const messedAroundAndGotATripleDouble = tripleThenDouble(2)
This is a simple example, but it shows how you can make many transformations on the same initial value.
这是一个简单的示例,但是它显示了如何在相同的初始值上进行许多转换。
Now imagine the initial value is the presentational component while the container is one of the functions that transforms the initial value. Mind blown!
现在想象一下,初始值是表示性组件,而容器是转换初始值的功能之一。 快炸死!
To start using recompose you need to pull in the recompose library. Under PACKAGES let’s add the recompose library.
要开始使用recompose,您需要引入recompose库。 在PACKAGES下,我们添加重组库。
{ “name”: “esnextbin-sketch”, “version”: “0.0.0”, “dependencies”: { “react”: “15.3.2”, “react-dom”: “15.3.2”, “recompose”: “latest”, “babel-runtime”: “6.11.6” }}
Going back to the CODE let’s import compose from recompose.
回到CODE,让我们从recompose导入compose 。
import { compose } from ‘recompose’
Then you can use compose to further abstract the higher-order component.
然后,可以使用compose进一步抽象高阶组件。
const HigherOrderComponent = compose( container( ‘https://fcctop100.herokuapp.com/api/fccusers/top/alltime' ))
And you can be more declarative about what the entire component is doing.
而且,您可以对整个组件的功能进行更多的声明。
const FetchAndDisplayFCCData = HigherOrderComponent(Presentational)
render(<FetchAndDisplayFCCData />, document.querySelector(‘#root’))
This has finally allowed you to create components that are versatile and flexible. You can even test your presentational components separately from higher-order components. Higher-order components FTW!
最终,您可以创建通用且灵活的组件。 您甚至可以与高级组件分开测试演示组件。 高阶组件FTW!
For kicks, Let’s update the presentational component to render a list of items instead of a big blob of data.
对于踢球,让我们更新演示组件以呈现项目列表,而不是大量数据。
const Presentational = ({ data }) => <ul> {data.map((v, k) => <li key={k}> {v.username} </li> )} </ul>
Whew! That was a lot. If you want to see the finished product take a look at the gist I created here.
ew! 好多 如果您想看成品,请看一下我在这里创建的要点。
For more information visit Andrew Clark’s great React utility library called recompose to learn more!
有关更多信息,请访问Andrew Clark强大的React实用程序库recompose,以了解更多信息!
acdlite/recomposerecompose - A React utility belt for function components and higher-order components.github.com
acdlite / recompose recompose-用于功能组件和高阶组件的React实用程序带。 github.com
翻译自: https://www.freecodecamp.org/news/react-higher-order-components-635d0bc38b6c/
react使用高阶组件好处