Skip to content

Latest commit

 

History

History
234 lines (160 loc) · 8.75 KB

Document.md

File metadata and controls

234 lines (160 loc) · 8.75 KB

Document

English | 中文

TypeScript 支持

We highly recommend to use region-core with TypeScript.

Know createRegion and createMappedRegion

region and mappedRegion share same bottom codes. The only difference is that mappedRegion stores data in key-value forms, while key is not needed in region (Or say: the key is internally assigned).

When you need to access value in mappedRegion, you need to specify the key, which is a very common pattern, such as using a userId to get a User type value.

Before knowing mappedRegion, let's know region first, all methods are one-to-one correspondence.

Create a region

In your application, you will create many region to manage data, they are separated from each other and they are global. This means that you can access the same data in different components, and the data does not change with the mount and unmount of the component. In most cases, you will set or load value to region in useEffect or useCallback.

  • Create a region with the following code:

    import { createRegion } from 'region-core';
    
    const region = createRegion<Value>();
  • You can pass in an initialValue:

    const region = createRegion<Value>(initialValue);

Assign value to region

We provide a number of methods to assign, load, get, and subscribe to the data you have in the region. These methods include set, load, loadBy, getXXX and useXXX.

  • Use region.set to assign value to region:

    const setTrue = () => {
        region.set(true);
    }
  • Similar to the usage of setState in react, you can pass in a function to change the value on the basis of the existing value:

    const toggle = () => {
        region.set(value => !value);
    }

Manage asynchronous tasks with region

  • region.loadBy will return an asynchronous function, usually you can name it loadXXX, when you call it, region will call the given asyncFunction and store the value it returns:

    type FetchUser = () => Promise<User>;
    const fetchUser: FetchUser = async () => {/* do something */};
    
    const loadUser = region.loadBy(fetchUser);
    
    useEffect(
        () => {
            loadUser();
        },
        []
    );

When loadFunc is called, region will mark loading: true, when it ends, it will mark loading: false, you can use useLoading to subscribe to it.

You can initiate multiple asynchronous loads at the same time, region will use a specific asynchronous strategy to handle the conflicts between multiple asynchronous, we will describe the strategy in detail later.

Sometimes we need to specify the initial loading value of region. region without any assignment is considered to be loading: true by default, but you can control this behavior through the startLoadingWith option.

  • loadFunc does not have to be used with useEffect, you can call loadFunc in onCallback:

    const Component = () => {
        const handleClick = useCallback(
            () => {
                loadUser();
            },
            []
        )
    
        return <button onClick={handleClick}>load user</button>;
    }
  • It can be used for prefetch, such as sending a request before ReactDOM's render:

    const main = () => {
        loadUser();
        ReactDOM.render(/**/);
    }
  • Usually asyncFunction can accept some parameters, in the corresponding loadFunc, you can pass these parameters:

    const fetchUser = async (params: Params): User => {/* do something */};
    const loadUser = region.loadBy(fetchUser);
    loadUser(params);
  • You can use reducer to process the returned data before it is stored.

    const region = createRegion<User[]>([]);
    
    const loadUser = region.loadBy(
        fetchUser,
        (state = [], result, params) => {
            return [...state, result];
        }
    );

You can also use region.load to handle asynchronous tasks, it is very similar to region.loadBy, but it accepts a promise.

You should notice that when you use load, asynchronous task is started before region could know, therefore throttle and race will not work as expected, you may need to handle them by yourself when you encounter related problems.

  • Use region.load to handle asynchronous tasks:

    const promise = asyncFunction(params);
    
    region.load(promise);

Subscribe to data and status changes with react hooks

  • Use useValue, useLoading, useError to subscribe to related changes:

    const Component = () => {
        const value = region.useValue();
        const loading = region.useLoading();
        const error = region.useError();
    
        // ...
        return <div>{value}</div>
    }

Where loading and error are related to asynchronous tasks, loading indicates whether the current region has an asynchronous task in progress. And value and error indicate the result of the last asynchronous task, success or failure.

Use get method to get value directly

  • You can use getValue, getLoading, getError to get the value directly, but be careful not to use them in react components, but to use them in situations where you are sure you should use them:

    const handler = () => {
      const value = region.getValue();
      const loading = region.getLoading();
      const error = region.getError();
      // ...
    }

Use mappedRegion to manage data in key-value forms

  • mappedRegion allows you to manage data in key-value forms. key can be of type string or multi-dimensional, such as {x: 0, y: 0}:

    import {createMappedRegion} from 'region-core';
    
    const mappedRegion = createMappedRegion<Key, Value>(initialValue);
    
    const Component = () => {
        const value = mappedRegion.useValue({x: 0, y: 0});
        // ...
    }
  • When you use mappedRegion, you need to specify a key before calling all methods, such as:

    mappedRegion.set({x: 0, y: 0}, 1);
    const value = mappedRegion.useValue({x: 0, y: 0}); // 1
  • Also in loadBy, you can specify a key from params:

    const loadUser = mappedRegion.loadBy(
        params => params.userId,
        fetchUser
    );

Synchronize data with localStorage

When creating region and mappedRegion, you can do some configuration to make region have additional features.

When configuring withLocalStorageKey, region will automatically synchronize with the corresponding item in localStorage when storing and accessing values, and you can communicate between multiple tabs through storage events.

  • Configure withLocalStorageKey:

    const userRegion = createRegion(initialUser, {withLocalStorageKey: 'user'});

Better asynchronous strategy

You can use strategy to configure asynchronous strategy. Currently, four asynchronous strategies are provided:

Strategy Description
acceptFirst When multiple asynchronous tasks are sent at the same time, only the first successful result is accepted. If there is already a successful return, the subsequent request will not be sent.
acceptLatest When multiple asynchronous tasks are sent at the same time, only the result of the last task sent is accepted, whether it is successful or failed.
acceptEvery When multiple asynchronous tasks are sent at the same time, all returns are accepted and processed in the order of arrival. Since the order of arrival may be out of order, you need to deal with the problem of out of order.
acceptSequenced When multiple asynchronous tasks are sent at the same time, the results are accepted in the order of task sending. When the middle task arrives, the results of the tasks sent before this task are no longer accepted, but the results of the tasks sent later are still accepted.

The default strategy is acceptSequenced, which meets most of the cases. When you need special optimization, you can choose other strategies.

  • Configure strategy:

    const userRegion = createRegion(initialUser, {strategy: 'acceptSequenced'});

Configure startLoadingWith

  • You can configure the initial loading value of region through startLoadingWith, which defaults to true.

    const userRegion = createRegion(initialUser, {startLoadingWith: false});