Use @redux-requests/react, redux-smart-Actions, and @redux-requests/react for bounce market

Let’s take a few steps to understand how the functionality is used and how to fix bugs

1

This is to do an asynchronous data fetch, the asynchronous function is to get the signature of the wallet (asynchronous), and save the channel redux function, look at the code handling

import { getQuery } from '@redux-requests/core';

const {
    data: { address },
} = getQuery(store.getState(), {
    type: setAccount.toString(),
    action: setAccount,
});
Copy the code

Corresponds to the setAccount code

import { createAction as createSmartAction } from 'redux-smart-actions';

export const setAccount = createSmartAction(
  'AccountActions/setAccount'.() = > ({
    request: {
      promise: (async function () {
        / /... Corresponding asynchronous code
        return {
          / /... Corresponding data...
          balance: newBigNumber(web3.utils.fromWei(balance)), }; }) ()},meta: {
      suppressErrorNotification: true.getData: (data: ISetAccountData) = > data,
      onSuccess: (response: { data: ISetAccountData }, action: RequestAction,) = > {
        const provider = response.data.provider;
        delete response.data.provider;
        if (action.meta) {
          action.meta.provider = provider;
        }
        returnresponse; }},}));Copy the code

That’s how short the business code is, getting the data directly.

There are two questions at this point

  • This is not a request, why is the data
  • How do you ask

For the first question, let’s analyze the way the data is obtained

We can see that there is a createSmartAction function. This is the createAction method in the Redux-smart-Actions library. Since it’s an action, it’s just getting the data. Let’s take a closer look at how it works.

The process is to get the getQuery method under @redux-requests/core and then execute and pass a createSmartAction

Redux: redux: redux: redux: redux: redux: redux: redux: redux: redux: redux: redux: redux: redux: redux: redux: redux: redux: redux.

But no matter how fancy the action is, it’s still just a dispatch process. The real data store still needs to be found in the store

Use @reduxJS/Toolkit configureStore to initialize the store, and @redux-requests/core to do reducer processing.

@redux-requests/core

@redux-requests/core is itself an extension of Axios, so it has features like caching. Race conditions, requests aborts, caching, optimistic updates, error handling

The official documentation

This is the Store configuration, which is quite different from normal writing, with details and raw data all hidden

  const configureStore = () = >{+const { requestsReducer, requestsMiddleware } = handleRequests({
+     driver: createDriver(axios),
+   });
+
    const reducers = combineReducers({
+     requests: requestsReducer,
    });
    conststore = createStore( reducers, + applyMiddleware(... requestsMiddleware), );return store;
  };
Copy the code

There’s one thing up there. Notice, there’s axios, @redux-requests/core which is the middleware of Axios, but with Redux. So you can use the same method as Axios for actions, which is a well-known library that you won’t be unfamiliar with.

But since redux is integrated, we can also generate a promise directly, so the above code has request. Promise, but as a request library, it is more like this to initiate the request, the action can be very simple, such as

const fetchBooks = () = > ({
  type: FETCH_BOOKS,
  request: {
    url: '/books'.// you can put here other Axios config attributes, like data, headers etc.}})Copy the code

When you add redux-smart-actions, it becomes

import { createAction } from 'redux-smart-actions'; const deleteBook = createAction('DELETE_BOOK', id => ({ request: { url: `/books/${id}`, method: 'delete', }, meta: { mutations: { FETCH_BOOKS: data => data.filter(book => book.id ! == id), }, }, }));Copy the code

But why redux-smart-Actions

redux-smart-actions

For action, there is one less type. But it also has thunk and createReducer capabilities

The official documentation

CreateAction: createAction: createAction: createAction: createAction: createAction: createAction: createAction: createAction: createAction: createAction

export const createAction = (name, action = () => ({})) = > {
  const actionCreator = (. params) = > ({ type: name, ... action(... params) }); actionCreator.toString =() = > name;
  return actionCreator;
}
Copy the code

2

In the first step we asked two questions, but the second one was left unanswered

How do I request it?

For the getBook example above, store. Dispatch (fetchBook(‘1’)) to get the data. (Because the library here is redux-Requests at its core, and this is redux-Requests in response.)

In practice, however, we don’t simply get the data; we also need to modify it. And setting the default data.

For asynchronous non-URL data, if you need to set the data for persistent storage or for other reasons, you need to set the data. For example, if you need to set the data for persistent storage, you need to set the data for persistent storage. How to do?

See this article for more information on react Web3 signature persistence

According to the actual situation, we can do a login persistence, such as signing the first time and not signing the second time, and get non-expired signature data from other applications, but the code of the data is not convenient to write directly in the action, so we can dispatch from the external, and then intercept and return according to the field.

Added persistence code

dispatch(setAccount({ address, token, chainId: chainId as BlockchainNetworkId, web3, balance, }))
Copy the code

In response to update

export const setAccount = createSmartAction(
  'AccountActions/setAccount'.(updateData? : ISetAccountData) = > ({
    request: {
      promise: (async function () {
        if (updateData) {
          return updateData
        }
      }
...
Copy the code

As we’ve seen above, it looks like the data was destined for createSmartAction, which had nothing to do with it, but was just a wrapper around redux-Requests

But meta suppressErrorNotification and getData with onSuccess is why, in addition to these properties, and without some important properties and use?

cache

The value of this attribute is true, and the value of this attribute represents the cache frequency, such as 10, which means that repeated requests will be cached within 10 seconds.

However, what happens when even the cache time needs to be rewritten?

cacheKey

This data is forced to cancel the key, which means that the cache is not removed when the CacheKey changes. The other one is to check the param parameter. The key value is called requestKey.

Because the cache is either stored in memory or cache disk, no matter where it is placed, the space is limited. If the amount of data is too large, the memory may be full and cause the lag. So you can limit the number of caches

requestCapacity

That’s what limits caching.

In addition to the cache number, you can use clearRequestsCache in cases where you need to force a flush

Both onSuccess and getData are data after a successful response, but there are differences in parameters and usage

onSuccess: (response, requestAction, store) => response
getData: data => any
Copy the code

ssr

ssr: ‘client’ | ‘server’

SRR is also supported, and so on. See handle-Requests for details

There’s a lot of meta support.

Graphql is supported for @redux-requests/ graphQL, which is easy to use.

configuration

import { handleRequests } from '@redux-requests/core';
import { createDriver } from '@redux-requests/graphql';

handleRequests({
  driver: createDriver({ url: 'http://localhost:3000/graphql' }),
});
Copy the code

use

import { gql } from '@redux-requests/graphql';

const fetchBooks = () = > ({
  type: 'FETCH_BOOKS'.request: {
    query: gql` { books { id title author liked } } `.headers: {
      SOMEHEADER: 'SOMEHEADER',}}});Copy the code

Meta actually almost finished, but there is still a suppressErrorNotification value, this I didn’t see inside the story – requests, then under the project code to send it.

In handleRequests, this is handled globally.

.onError: (error, action, store) = > {
    if(! action.meta? .suppressErrorNotification) { store.dispatch( NotificationActions.showNotification({message: extractMessage(error),
          severity: 'error',})); }throwerror; }});Copy the code

In addition, when searching, there is no need to manually cancel the request, repeated requests will automatically cancel the request and cancel the response.

3

BUY page code parsing

View

<Queries<
      ResponseData<typeof fetchItem>,
      ResponseData<typeof fetchWeb3PoolDetails>
    >
      requestActions={[fetchItem, fetchWeb3PoolDetails]}
    >
      {({ data: item }, { data: poolDetails }) = > (
      ---CODE---
Copy the code
dispatch(fetchItem({ contract: data.tokenContract, id: data.tokenId }));
Copy the code
export const fetchItem = createSmartAction<
  RequestAction<IApiNFTDetails, INFTDetails>
>('fetchItem'.(params: { contract: string; id: number }, meta) = > ({
  request: {
    url: '/api/v2/main/auth/getoneitembyid'.method: 'post'.data: { ct: params.contract, id: params.id },
  },
  meta: {
    getData: data= > mapNFTDetails(data),
    onRequest: (
      request: any,
      action: RequestAction,
      store: Store<RootState> & { dispatchRequest: DispatchRequest },
    ) = > {
      const { data } = getQuery(store.getState(), {
        type: setAccount.toString(),
        action: setAccount, }); request.data.accountaddress = data? .address;return request;
    },
    auth: true.driver: 'axiosSmartchain'.asMutation: false. meta, }, }));Copy the code

FetchWeb3PoolDetails and fetchItem are the same technology, except that the business is different.

The process is that the Queries component references the createSmartAction array and dispatch executes the action successfully. The data is returned to the final page and rendered directly.

Queries are a component that coordinates redux data and rendering. The task is to trigger the action and handle the exception. If it is normal, the data is returned.

export function Queries<T1 = void.T2 = void.T3 = void.T4 = void.T5 = void> ({ requestActions, children, requestKeys, noDataMessage, }: ILoadingProps
       ,>) {
  const queries = useAppSelector(state= >
    requestActions.map((item, index) = >
      getQuery(state, {
        type: item.toString(),
        action: item,
        requestKey: requestKeys? .[index], }), ), );if (isLoading(queries)) {
    return (
      noDataMessage || (
        <Box
          py={5}
          position="relative"
          width="100%"
          display="flex"
          justifyContent="center"
        >
          <QueryLoading />
        </Box>)); }const error = hasError(queries);

  if (error) {
    return <QueryError error={error} />;
  }

  if (isEmpty(queries)) {
    return <QueryEmpty />;
  }

  return <>{(children as any)(... queries)}</>;
}

Copy the code

– the –