react有自己的ui吗
Hooks are arguably one of the biggest paradigm shifts and game-changers in React’s short history. Although hooks are most frequently thought of and paraded around as some sort of harbinger of the death of class-based components, they have many other interesting uses. One of my favorite uses of hooks lately has been to use them as containers of logic and state, ensuring that their associated React components only have to deal with rendering UI as far as possible.
钩子可以说是React短历史上最大的范式转变和游戏规则改变者之一。 尽管钩子最常被认为是基于类的组件死亡的预兆,但它们还有许多其他有趣的用途。 最近,我最喜欢的钩子用法之一是将它们用作逻辑和状态的容器,以确保它们关联的React组件仅需要尽可能地处理呈现UI。
Hooks are commonly used for extracting common logic that is used across multiple components. Frequent use cases are API requests and form submissions. The approach I am advocating for in this article is to not just use hooks for reused logic, but for every logic in your app. In this way, your code will become significantly cleaner and manageable as your React components will only house the rendering code while your hook files will have all the logic related to that component. Consequently, your UI and logic become decoupled and you are free to reuse just the UI, the logic or both in other parts of your application.
挂钩通常用于提取在多个组件中使用的通用逻辑。 常见的用例是API请求和表单提交。 我在本文中提倡的方法不仅是将钩子用于重用的逻辑,而且还应将其用于应用程序中的每种逻辑。 这样,您的代码将变得更加清晰和易于管理,因为您的React组件将仅包含渲染代码,而钩子文件将具有与该组件相关的所有逻辑。 因此,您的UI和逻辑将解耦,您可以自由地在应用程序的其他部分中仅重用UI,逻辑或两者。
To illustrate this, we’re going to use as an example a list view component in a React application. The component will show a list of cards, each card having one user, fetched from the free ReqRes API, which supports pagination. We will implement pagination in this component so the user can click a “Load More” button to load more users without refreshing the page.
为了说明这一点,我们将以React应用程序中的列表视图组件为例。 该组件将显示一张卡片列表,每张卡片都有一个用户,可以从免费的ReqRes API(支持分页)中获取。 我们将在此组件中实现分页,以便用户可以单击“加载更多”按钮来加载更多用户,而无需刷新页面。
创建自己的钩子入门 (A Primer On Creating Your Own Hooks)
In this section, we’ll take a brief look at creating your own hooks. I’ll assume you are familiar with the basics of hooks as well common hooks like useState and useEffect. Creating and using your own hooks is straightforward as long as you remember the two golden rules of React hooks:
在本节中,我们将简要介绍如何创建自己的钩子。 我假设您熟悉钩子的基本知识以及诸如useState和useEffect之类的常见钩子。 只要您记住React钩子的两个黄金法则,创建和使用自己的钩子就很简单:
- Hooks can only be called in other hooks or functional components. 挂钩只能在其他挂钩或功能组件中调用。
- Hooks should be called at the top level (not inside conditions or loops) 挂钩应在顶层调用(而不是在内部条件或循环中)
When writing custom hooks, I find it best to think of hooks as simply functions that can store state and operate on that state. The function (hook) will usually return to its caller the state that it monitors as well as some methods that operate on that state. Since hooks can use other hooks (rule 1), we can use useState to store our custom hook’s state.
在编写自定义钩子时,我发现最好将钩子视为可以存储状态并对该状态进行操作的简单函数。 函数(挂钩)通常会将其监视的状态以及在该状态上运行的某些方法返回给其调用方。 由于钩子可以使用其他钩子(规则1),因此我们可以使用useState存储自定义钩子的状态。
Consider our scenario where we need to write the hook for pagination. What state will our hook keep? The most obvious one is how many of the items have already been loaded and what needs to be loaded next. Therefore, we’ll store the current page number in the state. Another thing we’ll need to store is the actual data that gets loaded from the API. Finally, we’ll keep track of whether there are further items to load or not.
考虑我们需要编写用于分页的钩子的场景。 我们的钩子将保持什么状态? 最明显的是已经加载了多少项,接下来需要加载什么。 因此,我们将在状态中存储当前页码。 我们需要存储的另一件事是从API加载的实际数据。 最后,我们将跟踪是否还有其他项目要加载。
传统方法有什么问题? (What’s wrong with the traditional approach?)
We’ll now look at two diagrams to see the comparison between two approaches. In the first one, we use the traditional approach and write our pagination logic inside the list component.
现在,我们将看两个图,以比较两种方法。 在第一个中,我们使用传统方法,并将分页逻辑写在list组件内。
Although this structure will get the job done perfectly fine, it has some drawbacks:
尽管此结构可以很好地完成工作,但它有一些缺点:
- The code of the UI rendering and javascript logic for fetching posts will get mixed up in one file, making it difficult to comprehend and reason about the code. UI呈现的代码和用于提取帖子的javascript逻辑将被混合在一个文件中,这使得很难理解和推理代码。
- It violates the single responsibility principle (SRP) of software engineering in which one unit of code should be responsible for one structured task (either rending UI or handling pagination logic) 它违反了软件工程的单一责任原则(SRP),在该原则中,一个代码单元应负责一项结构化任务(租赁UI或处理分页逻辑)
- If the same pagination logic is later required in other components of the app, we will end up writing the same code multiple times. 如果以后在应用程序的其他组件中需要相同的分页逻辑,我们将最终多次编写相同的代码。
- It will make our code files longer and tedious to navigate. 这将使我们的代码文件更长且繁琐的导航。
At this point, you might ask a very pertinent question:
此时,您可能会问一个非常相关的问题:
为什么不将处理函数移至单独的文件而不是创建钩子呢? (Why not just move the handler functions to a separate file instead of creating hooks?)
This will solve many of the problems we have outlined above as it will still separate the UI and pagination logic considerably. However there is one major limitation of this approach which hooks help us overcome: even if we move the function to a separate file and import it in the UserList component, UserList will still have to keep track of the page number.
这将解决我们上面概述的许多问题,因为它仍将UI和分页逻辑大大分开。 但是,这种方法的一个主要局限性是钩子可以帮助我们克服:即使将函数移到一个单独的文件中并将其导入到UserList组件中, UserList仍然必须跟踪页码。
UserList is just a UI component. It should only be responsible for rendering the list of users passed to it without any regard for the page number. The page number is purely a part of the pagination logic. It will be a violation of the SRP if UserList starts concerning itself with getting and setting page numbers. With a properly implemented pagination hook, any programmer using the UserList component will only have to worry about rendering the users. The details of the pagination mechanics will be abstracted away from the users of the pagination hook and they can focus on rendering the UI.
UserList只是一个UI组件。 它仅应负责呈现传递给它的用户列表,而无需考虑页码。 页码纯粹是分页逻辑的一部分。 如果UserList开始获取和设置页码,则将违反SRP。 有了正确实现的分页钩子,使用UserList组件的任何程序员都将只需要担心呈现用户。 分页机制的详细信息将从分页挂钩的用户那里抽象出来,他们可以专注于呈现UI。
Hooks can manage their own state (as well as use other hooks). This means they can manage the page number and update it as required. That’s what sets hooks apart from ordinary functions.
挂钩可以管理自己的状态(以及使用其他挂钩)。 这意味着他们可以管理页码并根据需要进行更新。 这就是将钩子与普通功能区分开的地方。
挂钩方法 (The Hooks Approach)
Now take a look at this second diagram in which we extract the pagination logic to a hook:
现在看一下第二个图,其中我们将分页逻辑提取到一个钩子中:
Here you can immediately see that the four problems we outlined above are solved.
在这里,您可以立即看到我们上面概述的四个问题已解决。
动手做 (Getting Hands On)
Now let’s implement our mini pagination example using hooks so you can get the hang of how to decouple code from UI.
现在,让我们使用钩子实现我们的迷你分页示例,这样您就可以掌握如何将代码与UI分离的方法。
- Initialize the app using CRA and set up folder structure. 使用CRA初始化应用并设置文件夹结构。
- Setup App.js 设置App.js
3. Create a card component for showing a single user
3.创建卡组件以显示单个用户
4. Create the User List component for showing a list of users.
4.创建用于显示用户列表的用户列表组件。
Here you will notice that we have used the usePaginationFromUrl hook (which we will create shortly). Recall that extracting the pagination logic to a hook means that our UserList component does not need to concern itself with any implementation detail. Therefore, we can simply go ahead and use the pagination hook as if it is already implemented and import from it the relevant variables and methods. This will serve as a guide for when we actually get to implementing the hook.
在这里,您会注意到我们使用了usePaginationFromUrl钩子(稍后将创建)。 回想一下,将分页逻辑提取到一个钩子意味着我们的UserList组件不需要关心任何实现细节。 因此,我们可以简单地继续使用分页挂钩,就好像它已经实现一样,并从中导入相关的变量和方法。 这将作为实际实现钩子的指南。
5. Create the pagination hook
5.创建分页钩
Our pagination hook stores 3 important pieces of state:
我们的分页钩存储3个重要状态:
pageNumber: The latest page number loaded by the hook. The user of the hook can increment this using the incrementPage method which then conveniently triggers the loading of the next page’s data, since pageNumber is a dependency of useEffect, inside which the next page is loaded.
pageNumber :挂钩加载的最新页码。 钩子的用户可以使用increasPage方法对该值进行递增,然后该方法可以方便地触发下一页数据的加载,因为pageNumber是useEffect的依赖项,在该依赖项中将加载下一页。
hasMoreData: A boolean that indicates whether there are further pages to be loaded or not. The API tells us the total number of pages in each response, so we can easily update this each time another page is fetched.
hasMoreData :一个布尔值,指示是否还有其他页面要加载。 该API告诉我们每个响应中的页面总数,因此,每次获取另一个页面时,我们都可以轻松地更新此页面。
data: The actual data loaded by the hook. This is an array containing all the users of the current and all previous pages loaded so far.
data :钩子加载的实际数据。 这是一个数组,其中包含到目前为止已加载的当前页面和所有先前页面的所有用户。
Note that the hook takes in a base url from the component that is using it. This will allow our hook to be reused with other API endpoints that also support pagination, assuming the key names in the data returned are consistent across the API. Even if the key names are not consistent, (for instance, you use another API instead that has the key totalPages instead of total_pages), you can pass these in as well to the hook, creating a completely reusable hook at the cost of some added parameters increasing code complexity.
请注意,该挂钩从使用它的组件中获取基本URL。 假设返回的数据中的键名在整个API中保持一致,这将使我们的钩子可以与也支持分页的其他API端点重用。 即使键名不一致(例如,您使用另一个具有键totalPages而不是total_pages的API),也可以将它们传递给该钩子,从而创建一个完全可重用的钩子,但要付出一些代价。参数增加了代码复杂度。
分页在行动 (Pagination In Action)
That’s it! Time to see the end result.
而已! 是时候看看最终结果了。
结语 (Wrapping Up)
React hooks are a great way to extract functionality that requires keeping track of state to a separate file. This leaves your React components with the sole responsibility of dealing with the UI instead of juggling between rendering the UI, keeping state, making API calls and implementing handler functions. This will make your code much easier to read and reason about and help you make cleaner mental models regarding your app’s functionality.
React挂钩是提取功能的好方法,该功能需要跟踪状态到单独的文件。 这使您的React组件负有处理UI的唯一责任,而不是在渲染UI,保持状态,进行API调用和实现处理程序功能之间进行折衷。 这将使您的代码更易于阅读和推理,并有助于您就应用程序的功能建立更清晰的思维模型。
翻译自: https://medium.com/swlh/decouple-your-logic-from-ui-by-creating-your-own-react-hooks-d291fd2d60dc
react有自己的ui吗