当前位置: 首页 > 编程日记 > 正文

编写react组件_React组件的“黄金法则”如何帮助您编写更好的代码

编写react组件

以及钩子如何发挥作用 (And how hooks come into play)

Recently I’ve adopted a new philosophy that changes the way I make components. It’s not necessarily a new idea but rather a subtle new way of thinking.

最近,我采用了一种新的理念,该理念改变了我制造零件的方式。 它不一定是新想法,而是一种微妙的新思维方式。

组件的黄金法则 (The Golden Rule of Components)

Create and define components in the most natural way, solely considering what they need to function.
以最自然的方式创建和定义组件,仅考虑其功能需要。

Again, it’s a subtle statement and you may think you already follow it but it’s easy to go against this.

同样,这是一个微妙的陈述,您可能会认为您已经遵循了它,但是很容易与此背道而驰。

For example, let’s say you have the following component:

例如,假设您具有以下组件:

If you were defining this component “naturally” then you’d probably write it with the following API:

如果您是“自然”地定义此组件,则可能会使用以下API编写它:

PersonCard.propTypes = {name: PropTypes.string.isRequired,jobTitle: PropTypes.string.isRequired,pictureUrl: PropTypes.string.isRequired,
};

Which is pretty straightforward — solely looking at what it needs to function, you just need a name, job title, and picture URL.

这非常简单-仅查看功能需要做什么,您只需要一个名称,职称和图片URL。

But let’s say you have a requirement to show an “official” picture depending on user settings. You might be tempted to write an API like so:

但是,假设您需要根据用户设置显示“官方”图片。 您可能会想编写这样的API:

PersonCard.propTypes = {name: PropTypes.string.isRequired,jobTitle: PropTypes.string.isRequired,officialPictureUrl: PropTypes.string.isRequired,pictureUrl: PropTypes.string.isRequired,preferOfficial: PropTypes.boolean.isRequired,
};

It may seem like the component needs those extra props to function, but in actuality, the component doesn’t look any different and doesn’t need those extra props to function. What these extra props do is couple this preferOfficial setting with your component and makes any use of the component outside that context feel really unnatural.

看起来组件似乎需要这些额外的道具才能起作用,但是实际上,该组件看上去并没有什么不同,并且不需要那些额外的道具来起作用。 这些额外的道具所做的就是将此preferOfficial设置与您的组件结合在一起,并使在上下文之外的任何组件使用都感觉非常不自然。

缩小差距 (Bridging the gap)

So if the logic for switching the picture URL doesn’t belong in the component itself, where does it belong?

因此,如果切换图片URL的逻辑不属于组件本身,则它属于什么位置?

How about an index file?

index文件呢?

We’ve adopted a folder structure where every component goes into a self-titled folder where the index file is responsible for bridging the gap between your “natural” component and the outside world. We call this file the “container” (inspired from React Redux’s concept of “container” components).

我们采用了文件夹结构,其中每个组件都进入一个自命名文件夹,其中index文件负责弥合“自然”组件与外界之间的鸿沟。 我们将此文件称为“容器”(灵感来自React Redux的“容器”组件概念 )。

/PersonCard-PersonCard.js ------ the "natural" component-index.js ----------- the "container"

We define containers as the piece of code that bridges that gap between your natural component and the outside world. For this reason, we also sometimes call these things “injectors”.

我们将容器定义为弥合自然成分与外界之间的鸿沟的一段代码。 因此,我们有时也将这些东西称为“注射器”。

Your natural component is the code you’d create if you were only shown a picture of what you were required make (without the details of how’d you’d get data or where it’d be placed in the app — all you know is that it should function).

您的自然组成部分是如果仅显示所需内容的图片而创建的代码(没有有关如何获取数据或将数据放置在应用程序中的详细信息,您所知道的全部是它应该起作用)。

The outside world is a keyword we’ll use to refer to any resource your app has (e.g. the Redux store) that can be transformed to satisfy your natural component’s props.

外部世界是一个关键字,我们将使用它来指代您的应用程序拥有的任何资源(例如Redux商店),这些资源可以进行转换以满足自然组件的需求。

Goal for this article: How can we keep components “natural” without polluting them with junk from the outside world? Why is that better?

本文的目标:如何使组件保持“自然”状态,而不会受到外界垃圾的污染? 为什么这样更好?

Note: Though inspired by Dan’s Abramov and React Redux’s terminology, our definition of “containers” goes slightly beyond that and is subtly different.

注意: 尽管受Dan的Abramov和React Redux的术语启发,但我们对“容器”的定义略有超出,并且有细微的不同。

The only difference between Dan Abramov’s container and ours is only at the conceptual level. Dan’s says there are two kinds of components: presentational components and container components. We take this a step further and say there are components and then containers.

Dan Abramov的容器与我们的容器之间的唯一区别只是在概念上。 Dan's说有两种类型的组件:呈现组件和容器组件。 我们将这一步骤更进一步,说有组件,然后是容器。

Even though we implement containers with components, we don’t think of containers as components on a conceptual level. That’s why we recommend putting your container in the index file — because it’s a bridge between your natural component and the outside world and doesn’t stand on its own.

即使我们使用组件来实现容器,我们也不认为容器在概念上是组件。 这就是为什么我们建议将您的容器放在index文件中的原因-因为它是您的自然组件与外界之间的桥梁,并且不能独立存在。

Though this article is focused on components, containers take up the bulk of this article.

尽管本文重点讨论组件,但是容器占据了本文的大部分内容。

Why?

为什么?

Making natural components — Easy, fun even.Connecting your components to the outside world — A bit harder.

制作自然组件-轻松,有趣,甚至可以将组件连接到外部世界-有点困难。

The way I see it, there are three major reasons you’d pollute your natural component with junk from the outside world:

我的看法是,您会用来自外部世界的垃圾污染天然成分的三个主要原因:

  1. Weird data structures

    奇怪的数据结构
  2. Requirements outside of the scope of the component (like the example above)

    超出组件范围的需求(如上面的示例)
  3. Firing events on updates or on mount

    在更新或挂载时触发事件

The next few sections will try to cover these situations with examples with different types of container implementations.

接下来的几节将尝试使用不同类型的容器实现的示例来涵盖这些情况。

使用奇怪的数据结构 (Working with weird data structures)

Sometimes in order to render the required information, you need to link together data and transform it into something that’s more sensible. For lack of a better word, “weird” data structures are simply data structures that are unnatural for your component to use.

有时为了呈现所需的信息,您需要将数据链接在一起并将其转换为更明智的信息。 由于缺少更好的词,“怪异”的数据结构只是组件不自然使用的数据结构。

It’s very tempting to pass weird data structures directly into a component and do the transforming inside the component itself, but this leads to confusing and often hard to test components.

将奇怪的数据结构直接传递到组件中并在组件本身内部进行转换是非常诱人的,但这会导致混乱,并且通常很难测试组件。

I caught myself falling into this trap recently when I was tasked to create a component that got its data from a particular data structure we use to support a particular type of form.

最近,我受命创建一个组件,该组件从用于支持特定类型表单的特定数据结构中获取数据时,陷入了这个陷阱。

ChipField.propTypes = {field: PropTypes.object.isRequired,      // <-- the "weird" data structureonEditField: PropTypes.func.isRequired,  // <-- and a weird event too
};

The component took in this weird field data structure as a prop. In practicality, this might’ve been fine if we never had to touch the thing again, but it became a real issue when we were asked to use it again in a different spot unrelated to this data structure.

该组件将这种奇怪的field数据结构作为支撑。 实际上,如果我们再也不必触碰它,这可能很好,但是当要求我们在与该数据结构无关的其他位置再次使用它时,这成为一个现实问题。

Since the component required this data structure, it was impossible to reuse it and it was confusing to refactor. The tests we originally wrote also were confusing because they mocked this weird data structure. We had trouble understanding the tests and trouble re-writing them when we eventually refactored.

由于该组件需要此数据结构,因此无法重复使用它,并且难以进行重构。 我们最初编写的测试也令人困惑,因为它们嘲笑了这个奇怪的数据结构。 最终重构时,我们很难理解测试并难以重写它们。

Unfortunately, weird data structures are unavoidable, but using containers is a great way to deal with them. One takeaway here is that architecting your components in this way gives you the option of extracting and graduating the component into a reusable one. If you pass a weird data structure into a component, you lose that option.

不幸的是,怪异的数据结构是不可避免的,但是使用容器是处理它们的好方法。 这里的一个要点是,以这种方式设计组件使您可以选择将组件提取并逐渐升级为可重用组件。 如果将怪异的数据结构传递给组件,则会丢失该选项。

Note: I’m not suggesting that all components you make should be generic from the beginning. The suggestion is to think about what your component does on a fundamental level and then bridge the gap. As a consequence, you’re more likely to have the option to graduate your component into a reusable one with minimal work.

注意: 我不建议您制作的所有组件从一开始就应该是通用的。 建议是从根本上考虑组件的功能,然后缩小差距。 因此,您更有可能选择以最少的工作将组件升级为可重用的组件。

使用功能组件实现容器 (Implementing containers using function components)

If you’re strictly mapping props, a simple implementation option is to use another function component:

如果您严格映射道具,则一个简单的实现选项是使用另一个功能组件:

import React from 'react';
import PropTypes from 'prop-types';import getValuesFromField from './helpers/getValuesFromField';
import transformValuesToField from './helpers/transformValuesToField';import ChipField from './ChipField';export default function ChipFieldContainer({ field, onEditField }) {const values = getValuesFromField(field);function handleOnChange(values) {onEditField(transformValuesToField(values));}return <ChipField values={values} onChange={handleOnChange} />;
}// external props
ChipFieldContainer.propTypes = {field: PropTypes.object.isRequired,onEditField: PropTypes.func.isRequired,
};

And the folder structure for a component like this looks something like:

此类组件的文件夹结构如下所示:

/ChipField-ChipField.js ------------------ the "natural" chip field-ChipField.test.js-index.js ---------------------- the "container"-index.test.js/helpers ----------------------- a folder for the helpers/utils-getValuesFromField.js-getValuesFromField.test.js-transformValuesToField.js-transformValuesToField.test.js

You might be thinking “that’s too much work” — and if you are then I get it. It may seem like there is more work to do here since there are more files and a bit of indirection, but here’s the part you’re missing:

您可能会想“这太麻烦了”-如果您愿意,我会明白的。 似乎有更多的工作要做,因为有更多的文件和一些间接调用,但这是您缺少的部分:

import { connect } from 'react-redux';import getPictureUrl from './helpers/getPictureUrl';import PersonCard from './PersonCard';const mapStateToProps = (state, ownProps) => {const { person } = ownProps;const { name, jobTitle, customPictureUrl, officialPictureUrl } = person;const { preferOfficial } = state.settings;const pictureUrl = getPictureUrl(preferOfficial, customPictureUrl, officialPictureUrl);return { name, jobTitle, pictureUrl };
};const mapDispatchToProps = null;export default connect(mapStateToProps,mapDispatchToProps,
)(PersonCard);

It’s still the same amount of work regardless if you transformed data outside of the component or inside the component. The difference is, when you transform data outside of the component, you’re giving yourself a more explicit spot to test that your transformations are correct while also separating concerns.

无论您是在组件外部还是在组件内部转换数据,这仍然是相同的工作量。 区别在于,当您在组件外部转换数据时,您将给自己一个更明确的位置来测试转换是否正确,同时还要分离关注点。

超出组件范围的履行要求 (Fulfilling requirements outside of the scope of the component)

Like the Person Card example above, it’s very likely that when you adopt this “golden rule” of thinking, you’ll realize that certain requirements are outside the scope of the actual component. So how do you fulfill those?

就像上面的“人卡”示例一样,当您采用这种“黄金法则”思考时,很可能会意识到某些要求超出了实际组件的范围。 那么,您如何实现这些目标呢?

You guessed it: Containers ?

您猜对了:容器?

You can create containers that do a little bit of extra work to keep your component natural. When you do this, you end up with a more focused component that is much simpler and a container that is better tested.

您可以创建一些容器来做一些额外的工作,以保持组件的自然状态。 当您这样做时,最终会得到更加集中的组件,该组件更加简单,并且容器得到了更好的测试。

Let’s implement a PersonCard container to illustrate the example.

让我们实现一个PersonCard容器来说明该示例。

使用高阶组件实现容器 (Implementing containers using higher order components)

React Redux uses higher order components to implement containers that push and map props from the Redux store. Since we got this terminology from React Redux, it comes with no surprise that React Redux’s connect is a container.

React Redux使用更高阶的组件来实现容器,这些容器可以推送和映射来自Redux商店的道具。 自从我们从React Redux获得了这个术语以来, React Redux的connect是一个容器就不足为奇了 。

Regardless if you’re using a function component to map props, or if you’re using higher order components to connect to the Redux store, the golden rule and the job of the container are still the same. First, write your natural component and then use the higher order component to bridge the gap.

无论您使用功能组件映射道具还是使用高阶组件连接到Redux商店,黄金法则和容器的工作都相同。 首先,编写自然分量,然后使用高阶分量弥合差距。

Folder structure for above:

上面的文件夹结构:

/PersonCard-PersonCard.js ----------------- natural component-PersonCard.test.js-index.js ---------------------- container-index.test.js/helpers-getPictureUrl.js ------------ helper-getPictureUrl.test.js

Note: In this case, it wouldn’t be too practical to have a helper for getPictureUrl. This logic was separated simply to show that you can. You also might’ve noticed that there is no difference in folder structure regardless of container implementation.

注意: 在这种情况下,为getPictureUrl提供帮助不会太实际。 分离此逻辑只是为了表明您可以。 您可能还已经注意到,无论容器实现如何,文件夹结构都没有区别。

If you’ve used Redux before, the example above is something you’re probably already familiar with. Again, this golden rule isn’t necessarily a new idea but a subtle new way of thinking.

如果您以前使用过Redux,则上面的示例可能已经很熟悉了。 同样,这一黄金法则不一定是一个新主意,而是一种微妙的新思维方式。

Additionally, when you implement containers with higher order components, you also have the ability to functionally compose higher order components together — passing props from one higher order component to the next. Historically, we’ve chained multiple higher order components together to implement a single container.

此外,当您使用具有较高顺序的组件实现容器时,还可以在功能上组合较高顺序的组件,从而将道具从一个较高顺序的组件传递到下一个。 从历史上看,我们将多个高阶组件链接在一起以实现单个容器。

2019 Note: The React community seems to be moving away from higher order components as a pattern.

2019注意: React社区似乎正在逐渐摆脱高阶组件。

I would also recommend the same. My experience when working with these is that they can be confusing for team members who aren’t familiar with functional composition and they can cause what is known as “wrapper hell” where components are wrapped too many times causing significant performance issues.

我也建议相同。 我在使用这些组件时的经验是,它们会使不熟悉功能组成的团队成员感到困惑,并且会导致所谓的“包装鬼”,其中组件被包装太多次,从而导致严重的性能问题。

Here are some related articles and resources on this: Hooks talk (2018) Recompose talk (2016) , Use a Render Prop! (2017), When to NOT use Render Props (2018).

以下是与此相关的一些文章和资源: Hooks talk (2018) Recompose talk (2016), 使用渲染道具! (2017), 何时不使用渲染道具 (2018)。

你答应过我 (You promised me hooks)

使用钩子实现容器 (Implementing containers using hooks)

Why are hooks featured in this article? Because implementing containers becomes a lot easier with hooks.

为什么在本文中使用钩子? 因为使用钩子实现容器变得容易得多。

If you’re not familiar with React hooks, then I would recommend watching Dan Abramov’s and Ryan Florence’s talks introducing the concept during React Conf 2018.

如果您不熟悉React钩子,那么我建议您看一下Dan Abramov和Ryan Florence在React Conf 2018期间介绍该概念的演讲 。

The gist is that hooks are the React team’s response to the issues with higher order components and similar patterns. React hooks are intended to be a superior replacement pattern for both in most cases.

要点是,挂钩是React团队对具有更高顺序组件和相似模式的问题的响应。 在大多数情况下,React挂钩都打算成为一种出色的替换方式。

This means that implementing containers can be done with a function component and hooks ?

这意味着可以通过功能组件和钩子来实现容器。

In the example below, we’re using the hooks useRoute and useRedux to represent the “outside world” and we’re using the helper getValues to map the outside world into props usable by your natural component. We’re also using the helper transformValues to transform your component’s output to the outside world represented by dispatch.

在下面的示例中,我们使用钩子useRouteuseRedux表示“外部世界”,并且使用助手getValues将外部世界映射为自然组件可用的props 。 我们还使用帮助程序transformValues将组件的输出transformValuesdispatch表示的外部世界。

import React from 'react';
import PropTypes from 'prop-types';import { useRouter } from 'react-router';
import { useRedux } from 'react-redux';import actionCreator from 'your-redux-stuff';import getValues from './helpers/getVaules';
import transformValues from './helpers/transformValues';import FooComponent from './FooComponent';export default function FooComponentContainer(props) {// hooksconst { match } = useRouter({ path: /* ... */ });// NOTE: `useRedux` does not exist yet and probably won't look like thisconst { state, dispatch } = useRedux();// mappingconst props = getValues(state, match);function handleChange(e) {const transformed = transformValues(e);dispatch(actionCreator(transformed));}// natural componentreturn <FooComponent {...props} onChange={handleChange} />;
}FooComponentContainer.propTypes = { /* ... */ };

And here’s the reference folder structure:

这是参考文件夹结构:

/FooComponent ----------- the whole component for others to import-FooComponent.js ------ the "natural" part of the component-FooComponent.test.js-index.js ------------- the "container" that bridges the gap-index.js.test.js         and provides dependencies/helpers -------------- isolated helpers that you can test easily-getValues.js-getValues.test.js-transformValues.js-transformValues.test.js

在容器中触发事件 (Firing events in containers)

The last type of scenario where I find myself diverging from a natural component is when I need to fire events related to changing props or mounting components.

我发现自己与自然组件有所不同的最后一种类型的场景是当我需要触发与更换道具或安装组件有关的事件时。

For example, let’s say you’re tasked with making a dashboard. The design team hands you a mockup of the dashboard and you transform that into a React component. You’re now at the point where you have to populate this dashboard with data.

例如,假设您要负责制作仪表板。 设计团队会为您提供仪表板的模型,然后将其转换为React组件。 现在,您必须在该仪表板中填充数据。

You notice that you need to call a function (e.g. dispatch(fetchAction)) when your component mount in order for that to happen.

您会注意到,在挂载组件时需要调用一个函数(例如dispatch(fetchAction) ),以使其发生。

In scenarios like this, I found myself adding componentDidMount and componentDidUpdate lifecycle methods and adding onMount or onDashboardIdChanged props because I needed some event to fire in order to link my component to the outside world.

在这种情况下,我发现自己添加了componentDidMountcomponentDidUpdate生命周期方法,并添加了onMountonDashboardIdChanged道具,因为我需要触发一些事件才能将组件链接到外界。

Following the golden rule, these onMount and onDashboardIdChanged props are unnatural and therefore should live in the container.

按照黄金法则,这些onMountonDashboardIdChanged道具是不自然的,因此应位于容器中。

The nice thing about hooks is that it makes dispatching events onMount or on prop change much simpler!

挂钩的好处在于,它使onMount或prop更改上的事件调度变得更加简单!

Firing events on mount:

在挂载时触发事件:

To fire an event on mount, call useEffect with an empty array.

要在挂载上触发事件,请使用空数组调用useEffect

import React, { useEffect } from 'react';
import PropTypes from 'prop-types';
import { useRedux } from 'react-redux';import fetchSomething_reduxAction from 'your-redux-stuff';
import getValues from './helpers/getVaules';
import FooComponent from './FooComponent';export default function FooComponentContainer(props) {// hooks// NOTE: `useRedux` does not exist yet and probably won't look like thisconst { state, dispatch } = useRedux();// dispatch action onMountuseEffect(() => {dispatch(fetchSomething_reduxAction);}, []); // the empty array tells react to only fire on mount// https://reactjs.org/docs/hooks-effect.html#tip-optimizing-performance-by-skipping-effects// mappingconst props = getValues(state, match);// natural componentreturn <FooComponent {...props} />;
}FooComponentContainer.propTypes = { /* ... */ };

Firing events on prop changes:

道具变更引发事件:

useEffect has the ability to watch your property between re-renders and calls the function you give it when the property changes.

useEffect能够在重新渲染之间监视您的属性,并在属性更改时调用您提供的功能。

Before useEffect I found myself adding unnatural lifecycle methods and onPropertyChanged props because I didn’t have a way to do the property diffing outside the component:

在使用useEffect之前,我发现自己添加了非自然的生命周期方法和onPropertyChanged道具,因为我没有办法在组件外部进行属性区分:

import React from 'react';
import PropTypes from 'prop-types';/*** Before `useEffect`, I found myself adding "unnatural" props* to my components that only fired events when the props diffed.** I'd find that the component's `render` didn't even use `id`* most of the time*/
export default class BeforeUseEffect extends React.Component {static propTypes = {id: PropTypes.string.isRequired,onIdChange: PropTypes.func.isRequired,};componentDidMount() {this.props.onIdChange(this.props.id);}componentDidUpdate(prevProps) {if (prevProps.id !== this.props.id) {this.props.onIdChange(this.props.id);}}render() {return // ...}
}

Now with useEffect there is a very lightweight way to fire on prop changes and our actual component doesn’t have to add props that are unnecessary to its function.

现在,借助useEffect ,可以使用一种非常轻量级的方式来更改道具,并且我们的实际组件不必添加对其功能不必要的道具。

import React, { useEffect } from 'react';
import PropTypes from 'prop-types';
import { useRedux } from 'react-redux';import fetchSomething_reduxAction from 'your-redux-stuff';
import getValues from './helpers/getVaules';
import FooComponent from './FooComponent';export default function FooComponentContainer({ id }) {// hooks// NOTE: `useRedux` does not exist yet and probably won't look like thisconst { state, dispatch } = useRedux();// dispatch action onMountuseEffect(() => {dispatch(fetchSomething_reduxAction);}, [id]); // `useEffect` will watch this `id` prop and fire the effect when it differs// https://reactjs.org/docs/hooks-effect.html#tip-optimizing-performance-by-skipping-effects// mappingconst props = getValues(state, match);// natural componentreturn <FooComponent {...props} />;
}FooComponentContainer.propTypes = {id: PropTypes.string.isRequired,
};

Disclaimer: before useEffect there were ways of doing prop diffing inside a container using other higher order components (like recompose’s lifecycle) or creating a lifecycle component like react router does internally, but these ways were either confusing to the team or were unconventional.

免责声明: useEffect之前,有一些方法可以使用其他更高阶的组件(例如recompose的lifecycle )在容器内进行useEffect ,或者创建一个像react router在内部创建的生命周期组件那样的方法,但是这些方法会使团队感到困惑或不合常规。

这有什么好处? (What are the benefits here?)

组件保持乐趣 (Components stay fun)

For me, creating components is the most fun and satisfying part of front-end development. You get to turn your team’s ideas and dreams into real experiences and that’s a good feeling I think we all relate to and share.

对我来说,创建组件是前端开发中最有趣,最令人满意的部分。 您可以将团队的想法和梦想变成真实的经验,这是我觉得我们都与之相关并分享的一种好感觉。

There will never be a scenario where your component’s API and experience is ruined by the “outside world”. Your component gets to be what you imagined it without extra props — that’s my favorite benefit of this golden rule.

绝不会出现“外部世界”破坏您组件的API和体验的情况。 您的组件将达到您的想象,而无需额外的道具-这是我最喜欢的黄金法则。

测试和重用的更多机会 (More opportunities to test and reuse)

When you adopt an architecture like this, you’re essentially bringing a new data-y layer to the surface. In this “layer” you can switch gears where you’re more concerned about the correctness of data going into your component vs. how your component works.

当采用这样的架构时,实际上是在表面上增加了一个新的数据Y层。 在这个“层”中,您可以切换齿轮,从而更加关注进入组件的数据的正确性以及组件的工作方式。

Whether you’re aware of it or not, this layer already exists in your app but it may be coupled with presentational logic. What I’ve found is that when I surface this layer, I can make a lot of code optimizations and reuse a lot of logic that I would’ve otherwise rewritten without knowing the commonalities.

无论您是否意识到,该层已经存在于您的应用程序中,但可能与表示逻辑结合在一起。 我发现,当我浮出水面时,我可以进行很多代码优化并重用很多我不知道通用性而不得不重写的逻辑。

I think this will become even more obvious with the addition of custom hooks. Custom hooks gives us a much simpler way to extract logic and subscribe to external changes — something that a helper function could not do.

我认为,通过添加自定义钩子,这一点将变得更加明显。 自定义钩子为我们提供了一种提取逻辑和订阅外部更改的简单得多的方法,而这是助手功能无法实现的。

最大化团队吞吐量 (Maximize team throughput)

When working on a team, you can separate the development of containers and components. If you agree on APIs beforehand, you can concurrently work on:

在团队中工作时,您可以分离容器和组件的开发。 如果您事先同意API,则可以同时进行以下工作:

  1. Web API (i.e. back-end)

    Web API(即后端)
  2. Fetching data from the web API (or similar) and transforming the data to the component’s APIs

    从Web API(或类似API)中获取数据并将数据转换为组件的API
  3. The components

    组成部分

有什么例外吗? (Are there any exceptions?)

Much like the real Golden Rule, this golden rule is also a golden rule of thumb. There are some scenarios where it makes sense to write a seemingly unnatural component API to reduce the complexity of some transformations.

就像真正的黄金法则一样,该黄金法则也是经验法则。 在某些情况下,编写看似不自然的组件API可以降低某些转换的复杂性。

A simple example would the names of props. It would make things more complicated if engineers renamed data keys under the argument that it’s more “natural”.

一个简单的例子就是道具的名称。 如果工程师在“更自然”的论点下重命名数据密钥,将使事情变得更加复杂。

It’s definitely possible to take this idea too far where you end up overgeneralizing too soon, and that can also be a trap.

绝对有可能将这个想法推到太远,以至于过早地过于概括,这也可能是一个陷阱。

底线 (The bottom line)

More or less, this “golden rule” is simply re-hashing the existing idea of presentational components vs. container components in a new light. If you evaluate what your component needs on a fundamental level then you’ll probably end up with simpler and more readable parts.

或多或少,这个“黄金法则”只是以一种新的方式重新散布了现有的表示性组件与容器性组件的概念。 如果从根本上评估组件的需求,那么最终可能会得到更简单,更易读的部分。

Thank you!

谢谢!

翻译自: https://www.freecodecamp.org/news/how-the-golden-rule-of-react-components-can-help-you-write-better-code-127046b478eb/

编写react组件

相关文章:

js验证函数摘录

/**本文摘自&#xff1a;http://www.cnblogs.com/rob0121/articles/1776298.html* js各种表单数据验证*/ /**************************************************************************************/ /*************************************数字的验证*********************…

React for循环渲染组件

通常你需要在一个组件中渲染列表。或者循环遍历渲染相同的多个组件,下面看看怎么实现: render() {const options = this.state.data.map(d => <Option key={d.value}>{d.text}</Option>);return (<SelectshowSearchvalue={this.state.value}placeholder={t…

让电脑的灵魂跟你走

想必我这个题目一出来&#xff0c;大家就知道我想写的是电脑远程控制了。 电脑远程控制是为了方便人们随时随地访问自己的电脑&#xff0c;从而进行更加灵活高效的工作。最常见的远程控制是我们利用客户端直接进入后台操作命令行界面。也就是终端shell。 电影里面&#xff0c;黑…

您尝试打开的文件_您是否尝试过重新打开软件团队的身份?

您尝试打开的文件by Victoriya Kalmanovich由Victoriya Kalmanovich 您是否尝试过重新打开软件团队的身份&#xff1f; (Have you tried turning your software team’s identity off and on again?) This series portrays my experience as an R&D group leader of a gr…

vijos 1006 晴天小猪历险记之Hill——数字三角形的终极变化

题目链接&#xff1a;https://vijos.org/p/1006 数字三角形原题看这里&#xff1a;http://www.cnblogs.com/huashanqingzhu/p/7326837.html 背景 在很久很久以前&#xff0c;有一个动物村庄&#xff0c;那里是猪的乐园&#xff08;^_^&#xff09;&#xff0c;村民们勤劳、勇敢…

电磁学讲义6:高斯定理计算电场

高斯定理是电场力平方反比定律和线性叠加原理的直接结果。也可以由高斯定理作为基本规律导出库仑定律。这说明高斯定理和库仑定律是不同形式的表示电荷和电场关系的同一规律。库仑定律可以使我们从电荷分布求出电场分布&#xff0c;高斯定理可以使我们从电场分布求出电荷分布。…

ant table表格整行点击事件并获取当前行的数据

实现效果:点击表格中某一行,或者点击表格中某一行的一个字段,获取当前行的 item 下标数据,并用 Link 标签传参,下一个页面接收的实现。 如果使用 router 跳转路由传参,需要导入 import router from umi/router; 如果用 Link 跳转路由传参,需要导入 import Link from u…

以太坊公链私链_如何使用以太坊构建汽车制造供应链系统

以太坊公链私链by Marcelo Russi Mergulho由Marcelo RussiMergulho 如何使用以太坊构建汽车制造供应链系统 (How to build a car manufacturing supply chain system using Ethereum) Here at Daitan we are always looking for new technologies that can help our clients s…

微信一次性订阅消息

微信一次性订阅消息官方文档&#xff1a;消息管理>发送一次性订阅消息 开发者可以通过一次性订阅消息授权让微信用户授权第三方移动应用&#xff08;接入说明&#xff09;或公众号&#xff0c;获得发送一次订阅消息给到授权微信用户的机会。授权微信用户可以不需要关注公众号…

react控制组件的显示或隐藏, 根据state判断元素显示隐藏 , setState不实时生效解决方法

代码实现功能&#xff1a;根据 state 中的值判断子组件显示或隐藏&#xff0c;因为 setState 不是及时生效的&#xff0c;所以不做显示隐藏判断会报错。 render() {// 客户经理循环组件function CommentSpan(props){const numbers props.managers;if(!numbers) return;const l…

关于R语言plyr包的安装问题

平时安装R包都是从Rstudio中进行的&#xff0c;今天在装plyr包的时候&#xff0c;Rstudio一直报错&#xff0c;示例如下&#xff1a; 是不是很无语啊&#xff0c;搞了半天不知所以然&#xff0c;然后突发奇想从Rgui中安装试下&#xff0c;没想到轻轻松松就成功了&#xff0c;示…

regexp 好汉字符串_如何在JavaScript中使用RegExp确认字符串的结尾

regexp 好汉字符串by Catherine Vassant (aka Codingk8)由凯瑟琳瓦森(Catherine Vassant)(又名Codingk8) 如何在JavaScript中使用RegExp确认字符串的结尾 (How to use a RegExp to confirm the ending of a String in JavaScript) Using the Regexp ?️ constructor使用Regex…

【转】浅谈分布式锁

前言 随着互联网技术的不断发展&#xff0c;数据量的不断增加&#xff0c;业务逻辑日趋复杂&#xff0c;在这种背景下&#xff0c;传统的集中式系统已经无法满足我们的业务需求&#xff0c;分布式系统被应用在更多的场景&#xff0c;而在分布式系统中访问共享资源就需要一种互斥…

php中的抽象类(abstract class)和接口(interface)

一、 抽象类abstract class 1 &#xff0e;抽象类是指在 class 前加了 abstract 关键字且存在抽象方法&#xff08;在类方法 function 关键字前加了 abstract 关键字&#xff09;的类。 2 &#xff0e;抽象类不能被直接实例化。抽象类中只定义&#xff08;或部分实现&#xff0…

React 父组件给子组件传值,子组件接收

父组件传值代码&#xff1a; render() {return (<div>{this.state.list?(<GeomLine list{this.state.list}/>):null}</div>);} 子组件接收代码&#xff1a; class GeomLine extends Component {// 在组件接收到一个新的 prop (更新后)时被调用。这个方法在…

unity 灯笼_如何创建将自己拼成文字的漂亮灯笼

unity 灯笼In this tutorial, we will go through how to create a group of festival lanterns that arrange themselves into the words you choose. An online demo can be found here.在本教程中&#xff0c;我们将介绍如何创建一组节日灯笼&#xff0c;这些灯笼将自己布置…

Android PackageManager packages.xml文件格式

packages.xml文件存放在/data/system目录下 该文件记录了系统中所有应用程序的包管理相关信息 PmS根据该文件进行包管理的各种操作 标签名称所包含的值举例last-platform-versioninternal"17" external"17"<permission-trees />暂时不使用<…

tplink wr886n v5.0 ttl 接线方法

我的倒是有ttl信息,但是全是乱码,换过RX和TX,也换过串口速率都没用,附上TTL接线图.2016-11-02今天晚上终于搞定了ttl了,步骤如下:1.先将串口波特率改为117500(推荐使用Putty).如果可以了就不用第二步了2.将usb转ttl转接板上的rx和tx的指示灯干掉,可以留下电源指示灯详细教程见s…

React子组件给父组件传值, 父组件引用子组件并给子组件传值

本博客代码是 React 父组件和子组件相互传值的 demo;实现封装一个折线图,折线图选择下拉框,获取下拉框点击的值并且传给父组件根据下拉框筛选的条件更新视图;效果图如下: 父组件代码: 代码解析:父组件 Parent 引用子组件 Sub ,传递了 list 组件给子组件,并且接收子组件…

我如何使用深度学习通过Fast.ai对医学图像进行分类

by James Dietle詹姆斯迪特尔(James Dietle) Convolutional Neural Networks (CNNs) have rapidly advanced the last two years helping with medical image classification. How can we, even as hobbyists, take these recent advances and apply them to new datasets? W…

Java——基础

1.数据类型 int&#xff0c;short&#xff0c;byte&#xff0c;long double&#xff0c;float char&#xff0c;String 2.变量 int var; var 12; int var1 12;final int v1 0; //常量 C/C变量的声明和定义是分开的&#xff0c;JAVA不区分。 //c/c extern int a; //声明 …

Gradle系列教程之依赖管理

这一章我将介绍Gradle对依赖管理的强大支持&#xff0c;学习依赖分组和定位不同类型仓库。依赖管理看起来很容易&#xff0c;但是当出现依赖解析冲突时就会很棘手&#xff0c;复杂的依赖关系可能导致构建中依赖一个库的多个版本。Gradle通过分析依赖树得到依赖报告&#xff0c;…

Ant Design Pro 登录流程以及路由权限设置

登录流程: 1.ant 框架最外层套了 SecurityLayout 布局 SecurityLayout 中判断用户是否登录,做自动跳转路由处理。 里面的 currentUser 和 currentUser.userid 很关键,是判断登录状态的值. 2.currentUser 是通过 src/models/user 中 fetchCurrent 绑定 type saveCurrentUs…

初级开发人员的缺点_这是我想放弃初级开发人员时所做的事情

初级开发人员的缺点Coding is hard. Really hard. There are times when you’ll think “this is amazing! I love this!”编码很难。 真的很难。 有时您会认为“这太神奇了&#xff01; 我喜欢这个&#xff01;” But you’ll also have the not so amazing times. The time…

C#之 HashSet(临时笔记,未参考资料,请慎重)

HashSet是一个集合&#xff0c;类似于DataSet,但是其主要用途是用来存放同一种类型的元素&#xff08;string、row、table等&#xff09;&#xff0c;如果添加的元素跟定义时初始的类型不一致&#xff0c;就会直接编译失败。 例如&#xff1a; HashSet<string> hsnew Has…

Ant Design of React从入门到开发教程

Ant Design Pro 是一个企业级中后台前端/设计解决方案。 目录: 一:开发前的准备 二:创建页面 三:创建组件并引用 四:封装网络请求和网络请求走向 五:登录流程以及路由权限设置 六:父组件和子组件相互传值和接收 七:for 循环渲染组件 Ant Design Pro 全家桶技术…

适合初学者的数据结构_数据结构101:数组-初学者的直观介绍

适合初学者的数据结构了解您每天使用的数据结构。 (Get to know the data structures that you use every day. ) Welcome! Let’s Start with some Vital Context. Let me ask you this: ✅ Do you listen to music on your smartphone?✅ Do you keep a list of contacts on…

少侠,找个千手观音来帮你营销可好?

亚历山大公司营销主管老张最近有点儿烦&#xff0c;不是因为老婆更年期、女儿叛逆期&#xff0c;而是工作遇到了些麻烦。 社交营销很火&#xff0c;老张自认为公司始终游走在新科技最前沿&#xff0c;当然在第一时间就开通了微信、微博、QQ……各种社交网络的一大堆账号&#x…

Upload上传图片

实现antd上传图片,Upload 组件可以上传多张图片,多张图片上传成功的效果图: 每次上传 onChange 回调函数都会执行一次并且里面接收一个JSON对象,其中 file 对象是本次上传的图片信息,status 值为 done 就表示这一次上传成功了,fileList 中是一个数组,里面是组件所有上传…

将html中的代码拷贝到jsp后出现的问题 Failed to create the part's controls

Failed to create the parts controls 解决方法&#xff1a; 在文件上右键:open with转载于:https://www.cnblogs.com/flyoung/p/4885921.html