在React Redux应用程序中处理宁静的请求数据

Handle RESTful Requests Data in React/Redux Apps

在React / Redux应用程序中处理RESTful请求数据

在React / Redux应用程序中处理RESTful请求数据 (Handle RESTful Requests Data in React/Redux Apps)

The idea is to handle modeling, fetching, and displaying RESTful requests data (Remote data) in React/Redux apps.

这个想法是在React / Redux应用程序中处理建模,获取和显示RESTful请求数据(远程数据)。

As a web developer, I have to deal with remote sources (e.g., HTTP) in my apps. During working with react, I was following an ordinary behavior by making the HTTP requests and then store the fetched data in the application store (e.g., redux store).

作为一名Web开发人员,我必须在我的应用程序中处理远程源(例如HTTP)。 在使用react的过程中,我通过发出HTTP请求来遵循通常的行为,然后将获取的数据存储在应用程序存储区(例如redux存储区)中。

It was a simple data type that maps the API response data. For example, if I fetch a list of users, each user has some properties (id, username, gender, etc…). The datatype that would represent that response is an array of User where User is the data type representing the user details.

这是映射API响应数据的简单数据类型。 例如,如果我获取用户列表,则每个用户都有一些属性(id,用户名,性别等)。 表示该响应的数据类型是一个User数组,其中User是表示用户详细信息的数据类型。

type User {
id: string,
username: string,
gender: 'Male' | 'Female'
.
.
.
}State = {
users: User[]
}

Suppose we want to display a loading placeholder while data is fetching and an empty view if the list of users is empty. The previous implementation (representation of data) doesn’t have much data that we can use to do so. We can add a loading flag to the State. Then in the UI, we check this flag before displaying the data.

假设我们要在获取数据时显示一个加载占位符,如果用户列表为空,则显示一个空视图。 以前的实现(数据表示)没有太多数据可用于实现此目的。 我们可以在状态中添加一个加载标志。 然后在用户界面中,我们在显示数据之前检查此标志。

type User {
id: string,
username: string,
gender: 'Male' | 'Female'
.
.
.
}State = {
loading: true,
users: User[]
}

There is no guarantee that you have to check this flag before displaying the list of users. If someone forgot, In slow connectivity, The empty placeholder may appear for seconds while data is loading. The previous implementation does not represent remote data well. So we need to find an explicit data model to represent RESTful requests data well in our application.

无法保证您必须在显示用户列表之前检查此标志。 如果有人忘记了,在慢速连接中,在加载数据时,空白占位符可能会显示几秒钟。 先前的实现不能很好地表示远程数据。 因此,我们需要找到一个明确的数据模型来很好地表示我们应用程序中的RESTful请求数据。

The following section inspired by RemoteData in elm.

下面的部分灵感 通过 RemoteData 在榆树

RemoteData类型 (RemoteData type)

RESTful requests have one of four states:

RESTful请求具有以下四种状态之一:

  • We haven’t asked for the data yet.

    我们尚未要求提供数据。
  • We’ve asked, but we haven’t got a response yet.

    我们已经问过,但还没有得到答复。
  • We got a response, but there was an error.

    我们得到了回应,但有一个错误。
  • We got a response, and here’s the data you asked.

    我们得到了回应,这是您要求的数据。

First, we will wrap our remote data type in a new model called RemoteData

首先,我们将远程数据类型包装在一个名为RemoteData的新模型中

Defining RemoteData type

定义 RemoteData 类型

RemoteData<T, E> where T is the data type and E is the error type respectively.

RemoteData<T, E>其中T是数据类型, E是错误类型。

So our state representation of users list example explained above will beHere we assume that our error type is a string

因此,我们上面解释的用户列表示例的状态表示为: 这里我们假定我们的错误类型是字符串

State = {
users: RemoteData<User[], string>
}

When we fetch a list of users from an API endpoint, there are four different states users can be:

当我们从API端点获取users列表时, users可以有四种不同的状态:

  • NOT_ASKED - You didn’t ask for the data yet

    NOT_ASKED您尚未请求数据

  • LOADING - You asked for the data but it’s not fetched yet.

    LOADING -您要求提供数据,但尚未提取。

  • REJECT - Something went wrong. Here's the error.

    REJECT -发生错误。 这是错误。

  • SUCCESS - Data fetched successfully. Here’s the requested data.

    SUCCESS -数据获取成功。 这是要求的数据。

And that’s it, You have now a better representation of remote data that will lead to a better UI.

就是这样,您现在可以更好地表示远程数据,从而带来更好的UI。

API请求包装器 (API request wrapper)

Since we now have a good representation of remote data, It’s time to handle the fetching of it and updating the application store. When calling an API endpoint to fetch data, we’ll need to update the application store, and since updating the application store in redux requires dispatching an action to tell reducer to update the store, I’ve created a helper function called api request wrapper based on Axios to do the job of making the HTTP requests and dispatching the reasonable action in each state of the HTTP request (loading, reject, and success).

由于我们现在可以很好地表示远程数据,因此现在该处理获取数据并更新应用程序存储的时候了。 调用API端点以获取数据时,我们需要更新应用程序商店,并且由于在redux中更新应用程序商店需要调度一个操作来告诉reducer更新商店,因此我创建了一个名为api request wrapper的辅助函数。基于Axios的工作来发出HTTP请求并在HTTP请求的每种状态(加载,拒绝和成功)中调度合理的操作。

Defining api request wrapper

定义 api 请求包装器

api<T, E>(config) where T, E are the types of data and the expected error respectively

api<T, E> (config)其中TE分别是数据类型和预期错误

api<User[], ErrorResponse>({
method: 'GET',
url: 'users',
baseURL: 'https://jsonplaceholder.typicode.com/',
action: FETCH_USERS,
});

Request Config

请求配置

In addition to Axios request config there are three more options:

除了Axios 请求配置外,还有三个选项:

  • action: is the action type that will get dispatched when the request state changed. If it’s not provided no action will get dispatched.

    action :是请求状态更改时将分派的操作类型。 如果未提供,则不会分派任何操作。

  • onSuccess, onError: are the callbacks to be triggered for the relevant request state.

    onSuccessonError :是为相关请求状态触发的回调。

The possible actions that can get dispatched from api request wrapper are:

可以从api请求包装程序中分派的可能动作是:

  • LOADING - You asked for the data but it’s not fetched yet.

    LOADING -您要求提供数据,但尚未提取。

  • REJECT - Something went wrong. Here's the error.

    REJECT -发生错误。 这是错误。

  • SUCCESS - Data fetched successfully. Here’s the requested data.

    SUCCESS -数据获取成功。 这是要求的数据。

The attribute that differentiates between loading, reject, and success of an action is the kind attribute.

区分加载,拒绝和动作成功的属性是kind属性。

Here’s some example of loading, reject, and success of fetch users list action.

这是加载,拒绝和成功获取用户列表操作的一些示例。

// Loading
{
action: 'FETCH_USERS',
kind: RemoteKind.Loading,
}// Reject
{
action: 'FETCH_USERS',
kind: RemoteKind.Reject,
error: 'Something went wrong'
}// Success
{
action: 'FETCH_USERS',
kind: RemoteKind.Success,
data: [{...}, {...}]
}

Defining Action type

定义 Action 类型

Action<T, E> where T is the data type and E is the error type respectively

Action<T, E>其中T是数据类型, E是错误类型

Instead of handling those actions by yourself for each HTTP request, api request wrapper will do that for you.

api请求包装器将代替您为每个HTTP请求自己处理这些操作。

Suppose you want to create an action for fetching users. Here’s an example that shows how the action file would look like with and without using the api request wrapper.

假设您要创建一个用于获取用户的操作。 这是一个示例,显示了使用和不使用api请求包装器时动作文件的外观。

Without using the api request wrapper, Your action file would be:

不使用 api 请求包装器,您的操作文件将是:

// action.tsconst FETCH_USERS = 'FETCH_USERS'
const FETCH_USERS_FAILED = 'FETCH_USERS_FAILED'
const FETCH_USERS_FULFILLED = 'FETCH_USERS_FULFILLED'const fetchUsers = () => (dispatch) => {
dispatch({type: 'FETCH_USERS'})
axios({
method: 'GET',
url: 'posts',
baseURL: 'https://jsonplaceholder.typicode.com/',
})
.then(res => dispatch({
type: FETCH_USERS_FULFILLED,
payload: res.data
})
.catch(err => dispatch({
type: FETCH_USERS_FAILED,
payload: err
})
}

By using the api request wrapper, it will be simpler, Just need to pass an extra param action that will get dispatched when the request state changed.

通过使用 api 请求包装器,它会变得更简单,只需要传递一个额外的param action ,该 action 将在请求状态更改时分派。

kind is the attribute differentiates between different request states (loading, reject, and success) of an action.

kind 是属性,用于区分动作的不同请求状态(加载,拒绝和成功)。

// actions.tsconst FETCH_USERS = 'FETCH_USERS'
const fetchUsers = () =>
api<User[], ErrorResponse>({
method: 'GET',
url: 'users',
baseURL: 'https://jsonplaceholder.typicode.com/',
action: FETCH_USERS,
});

获取数据缩减器 (Fetching data reducer)

Let’s catch the dispatched actions and update the application store. I’ve created a reducer that can handle the different actions for any remote data and update the store.

让我们捕获调度的动作并更新应用程序商店。 我创建了一个reducer,可以处理任何远程数据的不同操作并更新商店。

Defining fechingReducer

定义 fechingReducer

fetchingReducer<T, E>(actionType) a reducer for managing the state of the remote data.

fetchingReducer<T, E> (actionType)用于管理远程数据状态的缩减器。

import { fetchingReducer } from 'remote-data';combineReducers({
users: fetchingReducer<User[], ErrorResponse>(FETCH_USERS),
});
  • actionType: it should be the same as the action passed to the api request wrapper.

    actionType :它应该与传递给api请求包装程序的操作相同。

创建一个定制的reducer来手动更新商店(可选) (Creating a custom reducer to manually update the store (Optional))

You can create your custom reducer, here’s an example:

您可以创建您的自定义减速器,下面是一个示例:

import { RemoteData, RemoteKind, Action } from 'remote-data';
import { User, ErrorResponse } from '../../models';
import { FETCH_USERS } from './constants';
export type UsersStore = {
users: RemoteData<User[], ErrorResponse>;
};
const initialState: UsersStore = {
users: {
kind: RemoteKind.NotAsked,
},
};
export default (
state: UsersStore = initialState,
action: Action<User[], ErrorResponse>,
): UsersStore => {
if (action.type === FETCH_USERS) {
switch (action.kind) {
case RemoteKind.Loading:
return {
...state,
users: {
kind: RemoteKind.Loading,
},
};
case RemoteKind.Success:
return {
...state,
users: {
kind: RemoteKind.Success,
data: action.data,
},
};
case RemoteKind.Reject:
return {
...state,
users: {
kind: RemoteKind.Reject,
error: action.error,
},
};
default:
return state;
}
}
return state;
};
  • Initialize your state

    初始化您的状态
  • Verify the action type and kind

    验证动作类型和种类
  • Update your state

    更新您的状态

action is of type Action<T, E>

action的类型为Action <T,E>

远程组件 (Remote Component)

The last part is to handle the display of remote data in its different states.I’ve created a component that takes your remote data and the views that you want to display in each state Loading, Success, and Reject.

最后一部分是处理处于不同状态的远程数据的显示。我创建了一个组件,该组件接收远程数据以及要在每种状态LoadingSuccessReject显示的视图。

<RemoteComponent
remote={{ users }}
loading={UsersLoading}
reject={({ users }) => <UsersError error={users.error} />}
success={({ users }) => <ListUsers users={users.data} />}
/>

I’ve created a small react library that provides:

我创建了一个小的React库 ,该提供:

安装 (Install)

npm i @alismael/remote-data

用法 (Usage)

Performing a GET request to fetch the data

执行GET请求以获取数据

import { api } from 'remote-data';
import { Post, ErrorResponse } from '../models';
import { FETCH_POSTS } from './constants';const fetchPosts = () =>
api<Post[], ErrorResponse>({
method: 'GET',
url: 'posts',
baseURL: 'https://jsonplaceholder.typicode.com/',
action: FETCH_POSTS,
});

Adding a reducer to update the store

添加减速器以更新商店

import { Reducer } from 'react';
import { combineReducers } from 'redux';
import { fetchingReducer, RemoteData } from 'remote-data';
import { Post, ErrorResponse } from '../../models';
import { FETCH_POSTS } from './constants';export type PostsStore = {
posts: RemoteData<Post[], ErrorResponse>;
};const postsReducer: Reducer<PostsStore, any> = combineReducers({
posts: fetchingReducer<Post[], ErrorResponse>(FETCH_POSTS),
});export default postsReducer;

Displaying your remote data

显示您的远程数据

const PostsLoading = () => <>Loading posts...</>;
const PostsError = ({ err }: { err: ErrorResponse }) => <>{err}</>;
const ListPosts = ({ data }: { data: Post[] }) => <>Here you can use the fetched data</>type PostsContainerProps = {
fetchPosts: () => Promise<Post[]>;
posts: RemoteData<Post[], ErrorResponse>;
};const PostsContainer = ({ fetchPosts, posts }: PostsContainerProps) => {
React.useEffect(() => {
fetchPosts();
}, [fetchPosts]);return (
<RemoteComponent
remote={{ posts }}
loading={PostsLoading}
reject={({ posts }) => <PostsError error={posts.error} />}
success={({ posts }) => <ListPosts posts={posts.data} />}
/>
);
};const mapStateToProps = ({ posts }: StoreState) => ({
posts: posts.posts,
});
const mapDispatchToProps = (
dispatch,
) => ({
fetchPosts: () => dispatch(fetchPostsAction()),
});
connect(mapStateToProps, mapDispatchToProps)(PostsContainer);

GitHub: https://github.com/alismael/remote-dataNPM: https://www.npmjs.com/@alismael/remote-data

GitHub: https : //github.com/alismael/remote-data NPM: https : //www.npmjs.com/@alismael/remote-data

And that’s it. Thanks for reading.

就是这样。 谢谢阅读。

翻译自: https://medium.com/swlh/handle-restful-requests-data-in-react-redux-apps-23cee75f3324

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值