-
Notifications
You must be signed in to change notification settings - Fork 5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
深入理解 React 高阶组件 #4664
深入理解 React 高阶组件 #4664
Conversation
校对认领 |
@Raoul1996 好的呢 🍺 |
校对认领 |
@giddens9527 妥妥哒 🍻 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@CoderMing @leviding @Raoul1996 这是我第一次做校对,现在看到第116行。可能是我第一次做翻译的缘故,很多想法感觉与译者有些出入。不知道是否可以帮忙看一下我目前为止的校对意见,如果可以的话,那我就按照目前的程度继续校对。
|
||
 | ||
|
||
> There’s two important things to note before we get started. First, what we’re going to talk about is just a pattern. It’s not really even a React thing as much as it is a component architecture thing. Second, this isn’t required knowledge to build a React app. You could skip this post, never learn what we’re about to talk about, and still build fine React applications. However, just like building anything, the more tools you have available the better the outcome will be. If you write React apps, you’d be doing yourself a disservice by not having this in your “toolbox”. | ||
> 在这篇文章的开始之前,我们有两点需要注意:首先,我们所讨论的仅仅是一种设计模式。它甚至就像组件结构一样不是 React 里的东西。第二,它不是构建一个 React 应用所必须的知识。你可以关掉这篇文章、不学习在这篇文章中我们所讨论的内容,你仍然可以构建一个正常的 React 应用。不过,就像构建所有东西一样,你有更多可用的工具就会得到更好的结果。如果你在写 React 应用,在你的“工具箱”之中没有这个(React 高阶组件)的话会对你是非常不利的。 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
它甚至就像组件结构一样不是 React 里的东西 => 甚至比起属于 React,它更像是关于组件结构的内容。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
我对这儿的理解是:作者想说高阶组件就像组件结构一样,不是属于 React 的东西,这里并没有明确的高阶组件是组件结构的内容。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it is a component architecture thing. 这里的it应该指的是高阶组件吧,感觉两者是从属关系。
|
||
You can’t get very far into studying software development before you hear the (almost cultish) mantra of `Don't Repeat Yourself` or `D.R.Y`. Sometimes it can be taken a bit too far, but for the most part, it’s a worthwhile goal. In this post we’re going to look at the most popular pattern for accomplishing DRY in a React codebase, Higher-Order Components. However before we can explore the solution, we must first fully understand the problem. | ||
在你听到 `Don't Repeat Yourself` 或者 `D.R.Y` 这样的名言之前你是不会在软件开发的钻研之路上走得很远的。有时候实行这些名言会有点过于麻烦,但是在大多数情况下,(实行它)是一个有价值的目标。在这篇文章中我们将会去探讨在 React 库中实现 DRY 的最著名的模式——高阶组件。不过在我们探索答案之前,我们首先必须要完全明确问题来源。 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't Repeat Yourself 是否需要加一个翻译,放在括号里面?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
不需要吧,一般这种东西我倾向不翻译
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这个就不翻译了哈
@@ -111,11 +111,11 @@ class DailyChart extends React.Component { | |||
} | |||
``` | |||
|
|||
And with that, we’re all finished. You may have written React like this before. It’s not the end of the world (#shipit), but it’s not very “DRY”. As you saw, we’re repeating the exact same hover logic in every one of our components. | |||
这样的话,我们就全部做完了。你可能以前曾经这样写过 React 代码。这不是世界的结束 It’s not the end of the world (#shipit),但是它很不 “DRY”。正如我们所看到的,我们在我们的每一个组件中抖重复着逻辑很明确的鼠标悬停逻辑。 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
删掉It’s not the end of the world ?
|
||
At this point, the **problem** should be pretty clear, **we want to avoid duplicating our hover logic anytime a new component needs it**. So what’s the **solution**? Well before we get to that, let’s talk about a few programming concepts that’ll make the step to understanding the solution much easier, `callbacks` and `higher-order functions`. | ||
从这点看的话,**问题**问题变得非常清晰了:**我们希望避免在在每个需要添加鼠标悬停逻辑的组件是都再写一遍相同的逻辑**。所以,**答案**是什么?在我们开始前,让我们先讨论一些能让我们更容易理解答案的编程思想—— `回调函数` 和 `高阶函数`。 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
答案 => 解决办法
没问题,只是翻译风格不完全一样,不用翻译腔即可。 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@leviding @CoderMing 我这边校正完了
@@ -129,11 +129,11 @@ function addFive (x, addReference) { | |||
addFive(10, add) // 15 | |||
``` | |||
|
|||
Your brain might have got a little weird on this one if you’re not used to it. We pass the `add` function as an argument to the `addFive` function, rename it `addReference`, and then we invoke it. | |||
如果你没这样用过,你可能会感到困惑。我们将 `add` 函数作为一个参数传入 `addFive` 函数,重新命名为 `addReference`,然后我们出发了着个函数。 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
invoke 调用
|
||
Because vocabulary is important, here’s the same code with the variables re-named to match the concepts they’re demonstrating. | ||
因为这些名词很重要,下面是一份根据它们所表示的含义重新命名后的同样逻辑的代码。 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
重新命名变量后
@@ -183,7 +183,7 @@ addTen(10, add) // 20 | |||
addTwenty(10, add) // 30 | |||
``` | |||
|
|||
Again, this isn’t terrible, but we’re repeating a lot of the same logic. The goal here is to be able to create as many “adder” functions (`addFive`, `addTen`, `addTwenty`, etc) as we need, while minimizing code duplication. To accomplish this, what if we create a `makeAdder` function? This function can take in a number and a reference to the original `add` function. Because the goal of this function is to make a new adder function, we can have it return a brand new function that accepts the number to add. That was a lot of words. Let’s see some code. | |||
再一次出现这种情况,这样写并不糟糕,但是我们重复写了好多相似的逻辑。这里我们的目标是要能根据需要写很多 “adder” 函数(`addFive`、`addTen`、`addTwenty` 等等),同时尽可能减少代码重复。为了完成这个目标,我们创建一个 `makeAdder` 函数怎么样?着个函数可以传入一个数字和原始 `add` 函数。因为着个函数的目的是创建一个新的 adder 函数,我们可以让其返回一个全新的传递数字来实现加法的函数。这儿讲的有点多,让我们来看下代码吧。 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
着个函数 => 这个函数
|
||
``` | ||
state = { hovering: false } | ||
mouseOver = () => this.setState({ hovering: true }) | ||
mouseOut = () => this.setState({ hovering: false }) | ||
``` | ||
|
||
With that in mind, we want our higher-order component (which we’ll call `withHover`) to be able to encapsulate that hover logic in itself and then pass the `hovering` state to the component that it renders. That will allow us to prevent duplicating all the hover logic and instead, put it into a single location (`withHover`). | ||
哦绿到这一点,我们希望我们的高阶组件(我们把它称作 `withHover`)自身需要能包裹我们的鼠标悬停处理逻辑然后传递 `hovering` state 给其所需要渲染的组件。这将允许我们能够复用鼠标悬停逻辑,并将其装入单一的位置(`withHover`)。 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
哦绿到这一点 (typo)
|
||
* * * | ||
|
||
At this point we’ve covered all of the fundamentals of Higher-Order Components. There are still a few more important items to discuss though. | ||
在这一点上,我们已经涵盖到了高阶组件的所有基础知识。这里还有一些很重要的知识我们需要来说明下。 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
at this point 到现在或者至此?
@@ -355,7 +355,7 @@ function withHover(Component, propName = 'hovering') { | |||
} | |||
``` | |||
|
|||
Now we’ve set the default prop name to `hovering` (via ES6’s default parameters), but if the consumer of `withHover` wants to change that, they can by passing in the new prop name as the second argument. | |||
现在我们设置了默认的 prop 名称为 `hovering`(通过使用 ES6 的参数预设值来实现),如果用户想改变 `withHover` 的默认 prop 名的话,可以通过第二个参数来传递一个新的 prop 名。 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
default parameter 默认参数?
@@ -408,7 +408,7 @@ const InfoWithHover = withHover(Info) | |||
return <InfoWithHover height="16px" /> | |||
``` | |||
|
|||
The `height` prop gets passed to the `InfoWithHover` component. But what exactly is that component? It’s the component that we’re returning from `withHover`. | |||
`height` prop 通过 `InfoWithHover` 组件传入,但是事实上真的是它需要这个 prop 吗?当然不是,事实上是我们通过 `withHover` 所创建并返回的那个组件。 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
但是事实上真的是它需要这个 prop 吗? 当然不是,事实上是 => 但是这个组件是从哪儿来的?它是
|
||
When using a HOC, there’s an [inversion of control](https://en.wikipedia.org/wiki/Inversion_of_control) happening. Imagine we were using a third part HOC like React Router’s `withRouter` HOC. According to their docs, ”`withRouter` will pass `match`, `location`, and `history` props to the wrapped component whenever it renders.” | ||
当我们使用高阶组件时,会发生一些 [控制反转](https://en.wikipedia.org/wiki/Inversion_of_control) 的情况。想象下我们正在用类似于 React Router 的 `withRouter` 这类第三方的高阶组件。 根据它们的文档,“`withRouter` 将会在任何其被渲染的时候传递 `match`、`location 和 `history` prop 给其所包裹的组件”。 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
将会在任何其被渲染的时候传递 match
、location 和
history prop 给其所包裹的组件”。 => 将会在任何被它包裹的组件渲染时,将
match、
location 和 history
prop 传递给它们。
@@ -468,7 +468,7 @@ class Game extends React.Component { | |||
export default withRouter(Game) | |||
``` | |||
|
|||
Notice we’re not the ones creating the `Game` element (ie `<Game />`). We’re handing over our component entirely to React Router and we’re trusting them to not only render it, but also pass it the correct props. We saw this problem earlier when we talked about naming collisions with `hovering`. To fix that we decided to let the consumer of our `withHover` HOC pass in a second argument to configure what the prop name was going to be. With the 3rd party `withRouter` HOC, we don’t have that option. If our `Game` component is already using `match`, `location`, or `history`, we’re out of luck. We’d either have to modify those names in our component or we’d have to stop using the `withRouter` HOC. | |||
请注意,我们并没有(由 `<Game />` 组件直接)在界面上渲染 `Game` 元素。我们将我们的组件全权交给了 React Router 同时我们也相信其不止能正确渲染组件,也能正确传递 props。我们We’re handing over our component entirely to React Router and we’re trusting them to not only render it, but also pass it the correct props. 我们之前在讨论 `hovering` prop 命名冲突的时候看到过这个问题。为了修复这个问题我们尝试着给我们的 `withHover` 高阶组件传递第二个参数来允许修改 prop 的名字。但是在使用第三方高阶组件的时候,我们没有这个配置项。如果我们的 `Game` 组件已经使用了 `match`、`location` 或者 `history` 的话,就没有(像使用我们自己的组件)那没幸运了。我们除了改变我们之前所需要使用的 props 名之外就只能不使用 `withRouter` 高阶组件了。 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
没删掉原文?
|
||
You can’t get very far into studying software development before you hear the (almost cultish) mantra of `Don't Repeat Yourself` or `D.R.Y`. Sometimes it can be taken a bit too far, but for the most part, it’s a worthwhile goal. In this post we’re going to look at the most popular pattern for accomplishing DRY in a React codebase, Higher-Order Components. However before we can explore the solution, we must first fully understand the problem. | ||
在你听到 `Don't Repeat Yourself` 或者 `D.R.Y` 这样的名言之前你是不会在软件开发的钻研之路上走得很远的。有时候实行这些名言会有点过于麻烦,但是在大多数情况下,(实行它)是一个有价值的目标。在这篇文章中我们将会去探讨在 React 库中实现 DRY 的最著名的模式——高阶组件。不过在我们探索答案之前,我们首先必须要完全明确问题来源。 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
不需要吧,一般这种东西我倾向不翻译
|
||
 | ||
|
||
There are a few ways to approach this. The one you decide to go with is to detect the hover state of the individual components and from that state, show or not show the tooltip. There are three components you need to add this hover detection functionality to - `Info`, `TrendChart` and `DailyChart`. | ||
这里有好几种方式可以实现这个效果。其中一个你可能想到的是监听特定的组件的 hover 状态然后通过那个状态决定展示还是不展示提示框。在上图中,你有三个组件需要添加它们的监听函数—— `Info`、`TrendChart` 和 `DailyChart`。 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
其中一个你可能想到的是监听特定的组件的 hover 状态来决定是否展示 tooltip
|
||
At this point, the **problem** should be pretty clear, **we want to avoid duplicating our hover logic anytime a new component needs it**. So what’s the **solution**? Well before we get to that, let’s talk about a few programming concepts that’ll make the step to understanding the solution much easier, `callbacks` and `higher-order functions`. | ||
从这点看的话,**问题**问题变得非常清晰了:**我们希望避免在在每个需要添加鼠标悬停逻辑的组件是都再写一遍相同的逻辑**。所以,**答案**是什么?在我们开始前,让我们先讨论一些能让我们更容易理解答案的编程思想—— `回调函数` 和 `高阶函数`。 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
问题问题变得非常清晰了?
@@ -129,11 +129,11 @@ function addFive (x, addReference) { | |||
addFive(10, add) // 15 | |||
``` | |||
|
|||
Your brain might have got a little weird on this one if you’re not used to it. We pass the `add` function as an argument to the `addFive` function, rename it `addReference`, and then we invoke it. | |||
如果你没这样用过,你可能会感到困惑。我们将 `add` 函数作为一个参数传入 `addFive` 函数,重新命名为 `addReference`,然后我们出发了着个函数。 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
出发了着个函数?
@@ -205,18 +205,18 @@ addTen(10) // 20 | |||
addTwenty(10) // 30 | |||
``` | |||
|
|||
Cool. Now we can make as many “adder” functions as we need while minimizing the duplicate code we have to write. | |||
太酷了!现在我们可以在需要的时候随意地用最小的代码重复度创建 “adder” 函数。 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
最小的代码?
|
||
> If you care, this concept of having a function with multiple parameters return a new function with fewer parameters is called “Partial Application” and it’s a functional programming technique. JavaScript’s “.bind” method is a common example of this. | ||
> 如果你关心的话,这个通过一个多参数的函数来返回一个具有较少参数的函数的模式被叫做 “部分应用(Partial Application)“,它也是函数式编程的技术。JavaScript 内置的 “.bind“ 方法也是一个类似的例子。 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
关心 => 在意
* 是一个函数 | ||
* 有一个回调函数做为参数 | ||
* 返回一个新的函数 | ||
* 返回的这个函数会触发我们之前传入的回调函数 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
返回的函数会触发我们之前传入的回调函数
* 是一个组件 | ||
* 有一个组件做为参数 | ||
* 返回一个新的组件 | ||
* 返回的这个组件会渲染我们之前传入的组件 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
返回的组件
@@ -243,25 +243,25 @@ function higherOrderComponent (Component) { | |||
} | |||
``` | |||
|
|||
So now that we have the basic idea of what a higher-order component does, let’s start building ours out. If you’ll remember, the problem earlier was that we were duplicating all of our hover logic amongst all of the component that needed that functionality. | |||
我们已经有了一个高阶函数的基本概念了,现在让我们来构建它。如果你还记得的话,我们之前的问题是我们重复地在每个需要的组件上写我们的鼠标悬停的处理逻辑。 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
构建 => 完善
* Render the “Component” argument passing it a “hovering” prop. | ||
* 传入一个组件参数 | ||
* 返回一个新的组件 | ||
* 渲染传入参数的那个组件同时传递一个 “hovering” prop。 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
渲染传入的 “Component” 参数同时注入一个 “hovering” 属性。
pass 出于理解角度,翻译成为 注入。仅供参考
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
我看了下官方的文档,的确应该翻译为注入,谢谢
@leviding @Raoul1996 @giddens9527 谢谢大家提出校对意见,对于很多语句的修改的确比我的简洁干练好多。我已修改了部分问题,同时也有一些疑问,希望能再帮忙看看~ |
@CoderMing 我看了一下,是没修改完吗?例如 288 行的注入,看记录是采纳了这种译法,但是没有修改 |
@leviding 已修正并跟进译者的建议。 |
1 similar comment
@leviding 已修正并跟进译者的建议。 |
@CoderMing 已经 merge 啦~ 快快麻溜发布到掘金然后给我发下链接,方便及时添加积分哟。 掘金翻译计划有自己的知乎专栏,你也可以投稿哈,推荐使用一个好用的插件。 |
译文翻译完成,resolve #4643