react hooks使用_为什么要使用React Hooks?

react hooks使用

The first thing you should do whenever you're about to learn something new is ask yourself two questions -

每当您要学习新东西时,应该做的第一件事就是问自己两个问题-

  1. Why does this thing exist?

    为什么这东西存在?
  2. What problems does this thing solve?

    这东西能解决什么问题?

If you never develop a convincing answer for both of those questions, you won't have a solid enough foundation to build upon when you dive into the specifics. These questions are specifically interesting in regards to React Hooks. React was the most popular and most loved front-end framework in the JavaScript ecosystem when Hooks were released. Despite the existing praise, the React team still saw it necessary to build and release Hooks. Lost in the various Medium posts and blog think pieces on Hooks are the reasons (1) why and for what (2) benefit, despite high praise and popularity, the React team decided to spend valuable resources building and releasing Hooks. To better understand the answers to both of these questions, we first need to take a deeper look into how we've historically written React apps.

如果您对这两个问题都没有一个令人信服的答案,那么当您深入研究具体问题时,您将没有足够的坚实基础。 关于React Hooks,这些问题特别有趣。 当Hooks发布时,React是JavaScript生态系统中最受欢迎和最受欢迎的前端框架 。 尽管已有赞誉,但是React团队仍然认为有必要构建和发布Hooks。 在各个Medium帖子和博客上有关Hooks的文章中迷失的是原因(1)为什么为什么 (2)受益 ,尽管获得了很高的赞誉和欢迎,React团队还是决定花费宝贵的资源来构建和发布Hooks。 为了更好地理解这两个问题的答案,我们首先需要更深入地研究我们过去编写React应用程序的方式。

createClass (createClass)

If you've been around the React game long enough, you'll remember the React.createClass API. It was the original way in which we'd create React components. All of the information you'd use to describe the component would be passed as an object to createClass.

如果您在React游戏中React.createClass足够长的时间,您会记得React.createClass API。 这是我们创建React组件的原始方式。 您用来描述组件的所有信息都将作为对象传递给createClass

const ReposGrid = React.createClass({
  getInitialState () {
    return {
      repos: [],
      loading: true
    }
  },
  componentDidMount () {
    this.updateRepos(this.props.id)
  },
  componentDidUpdate (prevProps) {
    if (prevProps.id !== this.props.id) {
      this.updateRepos(this.props.id)
    }
  },
  updateRepos (id) {
    this.setState({ loading: true })

    fetchRepos(id)
      .then((repos) => this.setState({
        repos,
        loading: false
      }))
  },
  render() {
    const { loading, repos } = this.state

    if (loading === true) {
      return <Loading />
    }

    return (
      <ul>
        {repos.map(({ name, handle, stars, url }) => (
          <li key={name}>
            <ul>
              <li><a href={url}>{name}</a></li>
              <li>@{handle}</li>
              <li>{stars} stars</li>
            </ul>
          </li>
        ))}
      </ul>
    )
  }
})

💻 Play with the code.

with玩代码。

createClass was a simple and effective way to create React components. The reason React initially used the createClass API was because, at the time, JavaScript didn't have a built-in class system. Of course, this eventually changed. With ES6, JavaScript introduced the class keyword and with it a native way to create classes in JavaScript. This put React in a tough position. Either continue using createClass and fight against the progression of JavaScript or submit to the will of the EcmaScript standard and embrace classes. As history has shown, they chose the later.

createClass是创建React组件的一种简单有效的方法。 React最初使用createClass API的原因是因为当时JavaScript没有内置的类系统。 当然,这最终改变了。 在ES6中,JavaScript引入了class关键字,并以一种原生方式在JavaScript中创建类。 这使React处境艰难。 要么继续使用createClass对抗JavaScript的发展,要么顺应EcmaScript标准的意愿并拥抱类。 历史表明,他们选择了后者。

React.Component (React.Component)

We figured that we’re not in the business of designing a class system. We just want to use whatever is the idiomatic JavaScript way of creating classes. - React v0.13.0 Release

我们认为我们不是在设计类系统。 我们只想使用惯用JavaScript创建类的方法。 -React v0.13.0发布

React v0.13.0 introduced the React.Component API which allowed you to create React components from (now) native JavaScript classes. This was a big win as it better aligned React with the EcmaScript standard.

React v0.13.0引入了React.Component API,它允许您从(现在)本机JavaScript类创建React组件。 这是一个巨大的胜利,因为它使React更符合EcmaScript标准。

class ReposGrid extends React.Component {
  constructor (props) {
    super(props)

    this.state = {
      repos: [],
      loading: true
    }

    this.updateRepos = this.updateRepos.bind(this)
  }
  componentDidMount () {
    this.updateRepos(this.props.id)
  }
  componentDidUpdate (prevProps) {
    if (prevProps.id !== this.props.id) {
      this.updateRepos(this.props.id)
    }
  }
  updateRepos (id) {
    this.setState({ loading: true })

    fetchRepos(id)
      .then((repos) => this.setState({
        repos,
        loading: false
      }))
  }
  render() {
    if (this.state.loading === true) {
      return <Loading />
    }

    return (
      <ul>
        {this.state.repos.map(({ name, handle, stars, url }) => (
          <li key={name}>
            <ul>
              <li><a href={url}>{name}</a></li>
              <li>@{handle}</li>
              <li>{stars} stars</li>
            </ul>
          </li>
        ))}
      </ul>
    )
  }
}

💻 Play with the code.

with玩代码。

Though a clear step in the right direction, React.Component wasn't without its trade-offs.

尽管朝着正确的方向迈出了明确的一步,但React.Component并非没有取舍。

构造函数 (constructor)

With Class components, you initialize the state of the component inside of the constructor method as a state property on the instance (this). However, according to the ECMAScript spec, if you're extending a subclass (in this case, React.Component), you must first invoke super before you can use this. Specifically, when using React, you also have to remember to pass props to super.

使用Class组件,您可以将constructor方法内部的组件状态初始化为实例( this )的state属性。 但是,根据ECMAScript规范,如果要扩展子类(在本例中为React.Component ),则必须先调用super然后才能使用this 。 具体来说,在使用React时,您还必须记住将props传递给super

constructor (props) {
    super(props) // 🤮

    ...
  }
自动绑定 (Autobinding)

When using createClass, React would auto-magically bind all the methods to the component's instance, this. With React.Component, that wasn't the case. Very quickly, React developers everywhere realized they didn't know how the this keyword worked. Instead of having method invocations that "just worked", you had to remember to .bind methods in the class's constructor. If you didn't, you'd get the popular "Cannot read property setState of undefined" error.

使用createClass ,React会自动将所有方法绑定到组件的实例this 。 使用React.Component并非如此。 很快, 各地的React开发人员意识到他们不知道关键字的工作原理。 您必须记住在类的constructor .bind方法,而不是使用“工作正常”的方法调用。 如果您没有这样做,则会收到流行的“无法读取未定义的setState属性”错误。

constructor (props) {
    ...

    this.updateRepos = this.updateRepos.bind(this) // 😭
  }

Now I know what you might be thinking. First, these issues are pretty superficial. Sure calling super(props) and remembering to bind your methods is annoying, but there's nothing fundamentally wrong here. Second, these aren't necessarily even issues with React as much as they are with the way JavaScript classes were designed. Both points are valid. However, we're developers. Even the most superficial issues become a nuisance when you're dealing with them 20+ times a day. Luckily for us, shortly after the switch from createClass to React.Component, the Class Fields proposal was created.

现在我知道您可能在想什么。 首先,这些问题是肤浅的。 当然,调用super(props)并记住bind您的方法很烦人,但是这里根本没有错。 其次,与JavaScript类的设计方式相比,React甚至不一定有问题。 这两点均有效。 但是,我们是开发人员。 当您每天处理20次以上时,即使是最表面的问题也变得很麻烦。 对我们来说幸运的是,在从createClass切换到React.Component之后不久,创建了Class Fields提案。

类字段 (Class Fields)

Class fields allow you to add instance properties directly as a property on a class without having to use constructor. What that means for us is that with Class Fields, both of our "superficial" issues we previously talked about would be solved. We no longer need to use constructor to set the initial state of the component and we no longer need to .bind in the constructor since we could use arrow functions for our methods.

类字段允许您直接将实例属性添加为类的属性,而不必使用constructor 。 对我们而言,这意味着使用类字段可以解决我们之前讨论的两个“表面”问题。 我们不再需要使用constructor来设置组件的初始状态,并且我们不再需要在constructor .bind ,因为我们可以将箭头函数用于我们的方法。

class ReposGrid extends React.Component {
  state = {
    repos: [],
    loading: true
  }
  componentDidMount () {
    this.updateRepos(this.props.id)
  }
  componentDidUpdate (prevProps) {
    if (prevProps.id !== this.props.id) {
      this.updateRepos(this.props.id)
    }
  }
  updateRepos = (id) => {
    this.setState({ loading: true })

    fetchRepos(id)
      .then((repos) => this.setState({
        repos,
        loading: false
      }))
  }
  render() {
    const { loading, repos } = this.state

    if (loading === true) {
      return <Loading />
    }

    return (
      <ul>
        {repos.map(({ name, handle, stars, url }) => (
          <li key={name}>
            <ul>
              <li><a href={url}>{name}</a></li>
              <li>@{handle}</li>
              <li>{stars} stars</li>
            </ul>
          </li>
        ))}
      </ul>
    )
  }
}

💻 Play with the code.

with玩代码。

So now we're good, right? Unfortunately, no. The move from createClass to React.Component came with some tradeoffs, but as we saw, Class Fields took care of those. Unfortunately, there are still some more profound (but less talked about) issues that exist with all the previous versions we've seen.

所以现在我们很好,对吧? 抱歉不行。 从createClassReact.Component权衡取舍,但是正如我们所看到的,Class Fields负责这些。 不幸的是,我们所见过的所有先前版本仍然存在一些更深刻(但很少有人谈论)的问题。

The whole idea of React is that you're better able to manage the complexity of your application by breaking it down into separate components that you then can compose together. This component model is what makes React so elegant. It's what makes React, React. The problem, however, doesn't lie in the component model, but in how the component model is implemented.

React的整个想法是,通过将应用程序分解成可以组合在一起的独立组件,可以更好地管理应用程序的复杂性。 这个组件模型使React变得如此优雅。 这就是使React,React产生的原因。 但是,问题不在于组件模型,而在于如何实现组件模型。

重复逻辑 (Duplicate Logic)

Historically, how we've structured our React components has been coupled to the component's lifecycle. This divide naturally forces us to sprinkle related logic throughout the component. We can clearly see this in the ReposGrid example we've been using. We need three separate methods (componentDidMount, componentDidUpdate, and updateRepos) to accomplish the same thing - keep repos in sync with whatever props.id is.

从历史上看,我们构建React组件的方式已与该组件的生命周期结合在一起。 这种鸿沟自然迫使我们在整个组件中散布相关的逻辑。 在我们一直在使用的ReposGrid示例中,我们可以清楚地看到这一点。 我们需要三种单独的方法( componentDidMountcomponentDidUpdateupdateRepos )来完成同一件事-使reposprops.id是同步的。

componentDidMount () {
    this.updateRepos(this.props.id)
  }
  componentDidUpdate (prevProps) {
    if (prevProps.id !== this.props.id) {
      this.updateRepos(this.props.id)
    }
  }
  updateRepos = (id) => {
    this.setState({ loading: true })

    fetchRepos(id)
      .then((repos) => this.setState({
        repos,
        loading: false
      }))
  }

To fix this, we'd need a whole new paradigm for the way in which we'd handle side effects in React components.

为了解决这个问题,我们需要一个全新的范例来处理React组件中的副作用。

共享非视觉逻辑 (Sharing Non-visual Logic)

When you think about composition in React, odds are you think in terms of UI composition. This is natural since it's what React is so good at.

当您考虑React中的组合时,很可能会想到UI组合。 这很自然,因为这正是React擅长的。

view = fn(state)

Realistically, there's more to building an app than just the UI layer. It's not uncommon to need to compose and reuse non-visual logic. However, because React couples UI to a component, this can be difficult. Historically, React hasn't had a great answer for this.

实际上,构建应用程序不仅仅是UI层。 组成和重用非可视逻辑并不少见。 但是,由于React将UI耦合到组件,所以这可能很困难。 从历史上看,React对此并没有一个很好的答案。

Sticking with our example, say we needed to create another component that also needed the repos state. Right now, that state and the logic for handling it lives inside of the ReposGrid component. How would we approach this? Well, the simplest approach would be to copy all of the logic for fetching and handling our repos and paste it into the new component. Tempting, but nah. A smarter approach would be to create a Higher-Order Component that encapsulated all of the shared logic and passed loading and repos as props to whatever component needed it.

坚持我们的示例,假设我们需要创建另一个也需要repos状态的组件。 现在,该状态及其处理逻辑位于ReposGrid组件内部。 我们将如何处理呢? 好吧,最简单的方法是复制所有用于获取和处理存储repos的逻辑,然后将其粘贴到新组件中。 诱人,但不。 一种更聪明的方法是创建一个高阶组件 ,该组件封装了所有共享逻辑,并将loading和存储repos作为道具传递给所需的任何组件。

function withRepos (Component) {
  return class WithRepos extends React.Component {
    state = {
      repos: [],
      loading: true
    }
    componentDidMount () {
      this.updateRepos(this.props.id)
    }
    componentDidUpdate (prevProps) {
      if (prevProps.id !== this.props.id) {
        this.updateRepos(this.props.id)
      }
    }
    updateRepos = (id) => {
      this.setState({ loading: true })

      fetchRepos(id)
        .then((repos) => this.setState({
          repos,
          loading: false
        }))
    }
    render () {
      return (
        <Component
          {...this.props}
          {...this.state}
        />
      )
    }
  }
}

Now whenever any component in our app needed repos (or loading), we could wrap it in our withRepos HOC.

现在,只要应用程序中的任何组件需要repos (或loading ),我们都可以将其包装在withRepos HOC中。

// ReposGrid.js
function ReposGrid ({ loading, repos }) {
  ...
}

export default withRepos(ReposGrid)
// Profile.js
function Profile ({ loading, repos }) {
  ...
}

export default withRepos(Profile)

💻 Play with the code.

with玩代码。

This works and historically (along with Render Props) has been the recommended solution for sharing non-visual logic. However, both these patterns have some downsides.

这项工作可行,并且在历史上(连同Render Props一起 )一直是共享非可视逻辑的推荐解决方案。 但是,这两种模式都有一些缺点。

First, if you're not familiar with them (and even when you are), your brain can get a little wonky following the logic. With our withRepos HOC, we have a function that takes the eventually rendered component as the first argument but returns a new class component which is where our logic lives. What a convoluted process.

首先,如果您不熟悉它们(甚至当您不熟悉它们的话),那么按照逻辑,您的大脑也会变得有些不知所措。 使用withRepos HOC,我们有了一个函数,该函数将最终呈现的组件作为第一个参数,但是返回一个新的类组件,这是我们的逻辑所在。 多么复杂的过程。

Next, what if we had more than one HOC we were consuming. As you can imagine, it gets out of hand pretty quickly.

接下来,如果我们要消费多个HOC,该怎么办。 可以想象,它很快就失控了。

export default withHover(
  withTheme(
    withAuth(
      withRepos(Profile)
    )
  )
)

Worse than ^ is what eventually gets rendered. HOCs (and similar patterns) force you to restructure and wrap your components. This can eventually lead to "wrapper hell" which again, makes it harder to follow.

最终呈现的结果比^更糟糕。 HOC(和类似的模式)迫使您重组和包装组件。 最终可能导致“包装器地狱”,这又使跟踪变得更加困难。

<WithHover>
  <WithTheme hovering={false}>
    <WithAuth hovering={false} theme='dark'>
      <WithRepos hovering={false} theme='dark' authed={true}>
        <Profile 
          id='JavaScript'
          loading={true} 
          repos={[]}
          authed={true}
          theme='dark'
          hovering={false}
        />
      </WithRepos>
    </WithAuth>
  <WithTheme>
</WithHover>

当前状态 (Current State)

So here's where we're at.

这就是我们的位置。

  • React is hella popular.

    React非常受欢迎。
  • We use Classes for React components cause that's what made the most sense at the time.

    我们将类用于React组件,这是当时最有意义的原因。
  • Calling super(props) is annoying.

    调用super(props)很烦人。
  • No one knows how "this" works.

    没有人知道“这”是如何工作的。
  • OK, calm down. I know YOU know how "this" works, but it's an unnecessary hurdle for some.

    好冷静 我知道您知道“这”的工作原理,但这对某些人来说是不必要的障碍。
  • Organizing our components by lifecycle methods forces us to sprinkle related logic throughout our components.

    通过生命周期方法组织组件会迫使我们在整个组件中散布相关的逻辑。
  • React has no good primitive for sharing non-visual logic.

    React没有共享非可视逻辑的良好原语。

Now we need a new component API that solves all of those problems while remaining simple, composable, flexible, and extendable. Quite the task, but somehow the React team pulled it off.

现在,我们需要一个新的组件API,以解决所有这些问题,同时又保持简单可组合灵活可扩展 。 任务很不错,但是React团队以某种方式完成了任务。

React钩 (React Hooks)

Since React v0.14.0, we've had two ways to create components - classes or functions. The difference was that if our component had state or needed to utilize a lifecycle method, we had to use a class. Otherwise, if it just accepted props and rendered some UI, we could use a function.

从React v0.14.0开始,我们有两种创建组件的方法-类或函数。 区别在于,如果我们的组件具有状态或需要使用生命周期方法,则必须使用一个类。 否则,如果它只是接受道具并渲染了一些UI,则可以使用一个函数。

Now, what if this wasn't the case. What if instead of ever having to use a class, we could just always use a function.

现在,如果不是这样的话。 如果我们不必总是使用类,而总是可以使用函数呢?

Sometimes, the elegant implementation is just a function. Not a method. Not a class. Not a framework. Just a function.

有时,优雅的实现仅仅是一个功能。 不是方法。 不上课。 不是一个框架。 只是一个功能。

- John Carmack. Oculus VR CTO.

-约翰·卡马克。 Oculus VR CTO。

Sure we'd need to figure out a way to add the ability for functional components to have state and lifecycle methods, but assuming we did that, what benefits would we see?

当然,我们需要找到一种方法来增加功能组件具有状态和生命周期方法的能力,但是假设我们这样做了,我们将看到什么好处?

Well, we would no longer have to call super(props), we'd no longer need to worry about binding our methods or the this keyword, and we'd no longer have a use for Class Fields. Essentially, all of the "superficial" issues we talked about earlier would go away.

好了,我们不再需要调用super(props) ,我们不再需要担心bind我们的方法或this关键字,并且我们不再需要使用Class Fields。 本质上,我们之前讨论的所有“表面”问题都将消失。

(ノಥ,_」ಥ)ノ彡 React.Component 🗑

function ヾ(Ő‿Ő✿)

Now, the harder issues.

现在,更困难的问题。

  • State

  • Lifecycle methods

    生命周期方法
  • Sharing non-visual logic

    共享非视觉逻辑
(State)

Since we're no longer using classes or this, we need a new way to add and manage state inside of our components. As of React v16.8.0, React gives us this new way via the useState method.

由于我们不再使用类或this ,因此我们需要一种新的方式来添加和管理组件内部的状态。 从React v16.8.0开始,React通过useState方法为我们提供了这种新方法。

useState is the first of many "Hooks" you'll be seeing in this course. Let the rest of this post serve as a soft introduction. We'll be diving much deeper into useState as well as other Hooks in future sections.

useState是您在本课程中将会看到的许多“挂钩”中的第一个。 让本文的其余部分作为一个软介绍。 在以后的部分中,我们useState深入地研究useState以及其他Hook。

useState takes in a single argument, the initial value for the state. What it returns is an array with the first item being the piece of state and the second item being a function to update that state.

useState接受一个参数,即状态的初始值。 它返回的是一个数组,其中第一项是状态,第二项是更新状态的函数。

const loadingTuple = React.useState(true)
const loading = loadingTuple[0]
const setLoading = loadingTuple[1]

...

loading // true
setLoading(false)
loading // false

As you can see, grabbing each item in the array individually isn't the best developer experience. This is just to demonstrate how useState returns an array. Typically, you'd use Array Destructuring to grab the values in one line.

如您所见,单独获取数组中的每个项目都不是最佳的开发人员体验。 这只是为了演示useState如何返回数组。 通常,您将使用“数组解构”来将值捕获到一行中。

// const loadingTuple = React.useState(true)
// const loading = loadingTuple[0]
// const setLoading = loadingTuple[1]

const [ loading, setLoading ] = React.useState(true) // 👌

Now let's update our ReposGrid component with our new found knowledge of the useState Hook.

现在,使用对useState Hook的新发现知识来更新ReposGrid组件。

function ReposGrid ({ id }) {
  const [ repos, setRepos ] = React.useState([])
  const [ loading, setLoading ] = React.useState(true)

  if (loading === true) {
    return <Loading />
  }

  return (
    <ul>
      {repos.map(({ name, handle, stars, url }) => (
        <li key={name}>
          <ul>
            <li><a href={url}>{name}</a></li>
            <li>@{handle}</li>
            <li>{stars} stars</li>
          </ul>
        </li>
      ))}
    </ul>
  )
}

💻 Play with the code.

with玩代码。

  • State ✅

    州✅
  • Lifecycle methods

    生命周期方法
  • Sharing non-visual logic

    共享非视觉逻辑
生命周期方法 (Lifecycle methods)

Here's something that may make you sad (or happy?). When using React Hooks, I want you to take everything you know about the traditional React lifecycle methods as well as that way of thinking, and forget it. We've already seen the problem of thinking in terms of the lifecycle of a component - "This [lifecycle] divide naturally forces us to sprinkle related logic throughout the component." Instead, think in terms of synchronization.

这可能会使您难过(或高兴?)。 当我使用React Hooks时,我希望您掌握关于传统React生命周期方法以及这种思维方式的所有知识,而忘记它。 我们已经看到了根据组件的生命周期进行思考的问题-“这种[生命周期]划分自然会迫使我们在整个组件中散布相关的逻辑。” 相反,请考虑“ 同步”

Think of any time you've ever used a lifecycle event. Whether it was to set the initial state of the component, fetch data, update the DOM, anything - the end goal was always synchronization. Typically, synchronizing something outside of React land (an API request, the DOM, etc.) with something inside of React land (component state) or vice versa.

想想您曾经使用过生命周期事件的任何时间。 无论是设置组件的初始状态,获取数据,更新DOM,还是其他任何事情-最终目标始终是同步。 通常,将React Land之外的内容(API请求,DOM等)与React Land内的某些内容(组件状态)同步,反之亦然。

When we think in terms of synchronization instead of lifecycle events, it allows us to group together related pieces of logic. To do this, React gives us another Hook called useEffect.

当我们考虑同步而不是生命周期事件时,它使我们可以将相关的逻辑部分组合在一起。 为此,React给了我们另一个名为useEffect Hook。

Defined, useEffect lets you perform side effects in function components. It takes two arguments, a function, and an optional array. The function defines which side effects to run and the (optional) array defines when to "re-sync" (or re-run) the effect.

定义后, useEffect使您可以在功能组件中执行副作用。 它带有两个参数,一个函数和一个可选数组。 该函数定义要运行的副作用,(可选)数组定义何时“重新同步”(或重新运行)效果。

React.useEffect(() => {
  document.title = `Hello, ${username}`
}, [username])

In the code above, the function passed to useEffect will run whenever username changes. Therefore, syncing the document's title with whatever Hello, ${username} resolves to.

在上面的代码中,只要username更改,传递给useEffect的函数就会运行。 因此,将文档标题与Hello, ${username}解析的结果进行同步。

Now, how can we use the useEffect Hook inside of our code to sync repos with our fetchRepos API request?

现在,我们如何使用代码内部的useEffect Hook将useEffect reposfetchRepos API请求同步?

function ReposGrid ({ id }) {
  const [ repos, setRepos ] = React.useState([])
  const [ loading, setLoading ] = React.useState(true)

  React.useEffect(() => {
    setLoading(true)

    fetchRepos(id)
      .then((repos) => {
        setRepos(repos)
        setLoading(false)
      })
  }, [id])

  if (loading === true) {
    return <Loading />
  }

  return (
    <ul>
      {repos.map(({ name, handle, stars, url }) => (
        <li key={name}>
          <ul>
            <li><a href={url}>{name}</a></li>
            <li>@{handle}</li>
            <li>{stars} stars</li>
          </ul>
        </li>
      ))}
    </ul>
  )
}

💻 Play with the code.

with玩代码。

Pretty slick, right? We've successfully gotten rid of React.Component, constructor, super, this and more importantly, we no longer have our effect logic sprinkled (and duplicated) throughout the component.

很漂亮吧? 我们已经成功地摆脱了React.Componentconstructorsuperthis更重要的是,我们不再有我们的影响逻辑整个组件洒(和重复)。

  • State ✅

    州✅
  • Lifecycle methods ✅

    生命周期方法✅
  • Sharing non-visual logic

    共享非视觉逻辑
共享非视觉逻辑 (Sharing non-visual logic)

Earlier we mentioned that the reason React didn't have a great answer to sharing non-visual logic was because "React couples UI to a component". This lead to overcomplicated patterns like Higher-order components or Render props. As you can probably guess by now, Hooks have an answer for this too. However, it's probably not what you think. There's no built-in Hook for sharing non-visual logic, instead, you can create your own custom Hooks that are decoupled from any UI.

前面我们提到,React对共享非可视逻辑没有很好的答案的原因是“ React将UI耦合到组件”。 这会导致模式变得过于复杂,例如高阶组件渲染道具 。 您可能现在已经猜到了,胡克斯对此也有一个答案。 但是,这可能不是您的想法。 没有用于共享非可视逻辑的内​​置挂钩,而是可以创建与任何UI分离的自定义挂钩。

We can see this in action by creating our own custom useRepos Hook. This Hook will take in an id of the Repos we want to fetch and (to stick to a similar API) will return an array with the first item being the loading state and the second item being the repos state.

通过创建我们自己的自定义useRepos Hook,我们可以看到这一点。 该挂钩将获取我们要提取的存储库的id ,并(坚持使用类似的API)将返回一个数组,其中第一项为loading状态,第二项为存储repos状态。

function useRepos (id) {
  const [ repos, setRepos ] = React.useState([])
  const [ loading, setLoading ] = React.useState(true)

  React.useEffect(() => {
    setLoading(true)

    fetchRepos(id)
      .then((repos) => {
        setRepos(repos)
        setLoading(false)
      })
  }, [id])

  return [ loading, repos ]
}

What's nice is any logic that's related to fetching our repos can be abstracted inside of this custom Hook. Now, regardless of which component we're in and even though it's non-visual logic, whenever we need data regarding repos, we can consume our useRepos custom Hook.

很好的是,与获取我们的repos有关的任何逻辑都可以在此自定义Hook中抽象。 现在,无论我们使用哪个组件,即使它是非可视逻辑,只要需要有关repos数据,我们都可以使用useRepos自定义Hook。

function ReposGrid ({ id }) {
  const [ loading, repos ] = useRepos(id)

  ...
}
function Profile ({ user }) {
  const [ loading, repos ] = useRepos(user.id)

  ...
}

💻 Play with the code.

with玩代码。

  • State ✅

    州✅
  • Lifecycle methods ✅

    生命周期方法✅
  • Sharing non-visual logic ✅

    共享非视觉逻辑✅


The marketing pitch for Hooks is that you're able to use state inside function components. In reality, Hooks are much more than that. They're about improved code reuse, composition, and better defaults. There's a lot more to Hooks we still need to cover, but now that you know WHY they exist, we have a solid foundation to build on.

Hooks的营销策略是,您可以在功能组件内部使用状态。 实际上,Hooks远不止于此。 它们旨在改善代码的重用性,组合和更好的默认值。 Hooks还有很多需要我们解决的问题,但是现在您知道为什么它们存在了,我们有了一个坚实的基础。

这是我们的React Hooks课程的一部分
如果您喜欢这篇文章,请查看。 (This is part of our React Hooks course.
If you enjoy this post, check it out.)

翻译自: https://www.freecodecamp.org/news/why-react-hooks/

react hooks使用

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值