GithubHelp home page GithubHelp logo

regionjs / region-core Goto Github PK

View Code? Open in Web Editor NEW
114.0 3.0 5.0 32.11 MB

Progressive View Model Management Library

Home Page: https://regionjs.github.io/region-core

License: MIT License

HTML 0.38% CSS 0.36% TypeScript 98.36% Shell 0.09% JavaScript 0.81%
react swr redux typescript

region-core's Introduction

region-core

version npm downloads codecov MIT License

region-core is a progressive View Model Management Framework. You can use it while using react state, redux, and benefit from it.

English | 中文

Get Started

  • install
npm i region-core
  • Build your Component above region
import {createRegion} from 'region-core';

const region = createRegion<string>('initialValue');

const handleChange = e => region.set(e.target.value);

const Component = () => {
    const value = region.useValue();
    return <input value={value} onChange={handleChange} />;
};
  • Fetching data with region
import {createRegion} from 'region-core';

const region = createRegion<User>();

const loadUser = region.loadBy(asyncFuncion);

// call loadUser in application lifecycle
loadUser({userId: 1});

const Component = () => {
    const value = region.useValue();
    const loading = region.useLoading();
    const error = region.useError();

    // ...
    return <div>{value}</div>;
}

Docs

Document And Best Practices

Migrate Guide

ChangeLog

Request for Comments

Example

Online Example

git clone https://github.com/regionjs/region-core.git
cd example
npm i
npm start

SSR: NextJs with Region

Contribute

Feel free to raise issues and PR.

region-core's People

Contributors

conwnet avatar dancerphil avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

region-core's Issues

Clear error when load start

Is your feature request related to a problem? Please describe.

We have

const { loading, error, result } = region.useProps('result');
if (loading) {
  return 'loading...';
}
if (error) {
  return 'error!';
}
return ...

It's fine.

But when

const { loading, error, result } = region.useProps('result');
if (error) {
  return 'error!';
}
return ... // which deals with loading

And it's not fully worked.

It must be

if (!loading && error) {
  return 'error!';
}

Describe the solution you'd like
Clear error when load start.

Describe alternatives you've considered
/

Additional context
/

useSuspense

Is your feature request related to a problem? Please describe.
It is possible to benefit from React.Suspense. But I'm not sure if there is some trap implement it.

Describe the solution you'd like

<Suspense fallback={<h1>Loading...</h1>}>
  <Component />
</Suspense>

loadUser();

const Component = () => {
  useSuspense();
  // user must exists
  const user = useValue();
}

Describe alternatives you've considered
It is also likely to implement

const Component = () => {
  // user must exists
  const user = useSuspenseValue();
}

, but developers may need other attributes of region

const Component = () => {
  useSuspenseValue();
  const error = useError();
}

, it is wired to call useSuspenseValue without using its value.

Additional context
It should simplify code like

const Component = () => {
  const loading = useLoading();
  const value = useValue();
  if (loading) {
    return <Loading />
  }
  return ...
}

, also it get the benefit of Suspense like fallback and expireMs

Keep localStorage value cached

Describe the bug
After 11.8.1,localStorage value is not cached.

Reproduce Link
/

Current Behavior
/

Expected behavior
Cache localStorage if its value is equal (compares in string form)

Package Version
11.8.1

Environment
/

Additional context
Also do not set value into region if storage event passed a string-equal value.

Maybe cache a string value in ref.

combinedRegion should always returns loading as boolean

Describe the bug
combinedRegion should always returns loading as boolean

To Reproduce
const loading = combinedRegion.getLoading(['a', 'b']) Returns an array of boolean

Expected behavior
Returns a boolean

Additional context
/

effect

Is your feature request related to a problem? Please describe.
An effect api in order to deal with effect outside view (like React.useEffect).

Describe the solution you'd like

const cancel = region.effect(['a', 'b'], 'sum', ({a, b}) => a + b);

```javascript
// then you can
region.set('a', 1);
region.set('b', 2);
region.getProps('sum'); // { sum: 3 }

// also forward loading
region.load('a', ...);
region.getProps('sum'); // { loading: true, ... }
// another case
region.effect('complexObject', 'partA', ({ complexObject }) => complexObject.partA);
region.effect('complexObject', 'partB', ({ complexObject }) => complexObject.partB);

region.load('complexObject', ...);
region.getProps('partA'); // { loading: true, ... }

Describe alternatives you've considered

region.pipe(['a', 'b'], 'sum', ({a, b}) => a + b);

Additional context
/

createHandler & useHandler

Is your feature request related to a problem? Please describe.

I'm thinking about data flow.

Clearly sometimes we pass some props not for rendering, but just for build the params for a callback.

It is not worth extra rendering if params changes. So I'm proposing createHandler & useHandler.

Describe the solution you'd like

const urlTemplate = '/rest/companies/{companyId}/users/{userId}/followers'

const handleClick = region.createHandler(
  ['company', 'user'],
  async ({ company, user }) => {
    const followers = await get(urlTemplate)({ companyId: company.id, userId: user.id });
    ...
  },
);

const Component = ({ userId }) => {
  const handleClick = region.useHandler(
    'company',
    async ({ company }) => {
      const followers = await get(urlTemplate)({ companyId: company.id, userId: userId });
      ...
    },
    [userId],
  );
};

Describe alternatives you've considered
/

Additional context
The main idea of region-core is that it focus on data life cycle. And data life cycle is separate from react life cycle.

Since getProps inside Component is always dangerous. I want to provide a simple way for developer and they don’t need to know the internal algorithms to get optimized.

loadingPattern

Is your feature request related to a problem? Please describe.
There is two loadingPattern now, strictLoading: true & strictLoading: false. But they are in region scope.

Describe the solution you'd like

/**
 * @param loadingPattern 'default' | 'isEmpty' | 'onlyPending'
 */
region.getProps(['user', 'follower'], { loadingPattern: ... });
  • default

when something is pending, returns loading: true. Also when nothing is set or load, returns loading: true

  • isEmpty

only when data is empty returns loading: true

  • onlyPending

when something is pending, returns loading: true. But returns loading: false when nothing is set or load.

  • func(optional & need refactor)
const func = ({loading, result, fetchTime, error}) => ...;

const loading = entities.reduce((entity, preLoading) => {
  const nextLoading = func(entity);
  return preLoading || nextLoading;
}, false)

Describe alternatives you've considered
/

Additional context
/

[Best Practice]: Also use `constate` to manage `local data`

region-core 从设计之初就只考虑储存全局数据,这意味着在某些场景下强行使用 region-core 并不是一个好的做法,为了更好的使用 region-core 开发你的业务,你需要意识到哪些需求是 不适合 使用 region-core 来实现的。

在页面加载时使用 HTTP 获取数据,储存到 region 中,并在大量的子组件中使用同一份数据

非常推荐使用 region-core 完成。

控制一些全局的变量,比如某个弹框的开关(弹框仅会出现一个),或者当前处于 active 的某个对象(active 对象仅有一个)

推荐使用 region-core 完成,你可以自由控制相关的 region 而不需要通过 Provider 和 Context 来获取相关的 handler,这将降低你的代码和上下文的耦合。

全局状态,根据 id 的不同,希望获取不同的数据

非常推荐使用 region-core 完成。

局部状态,期望随着组件的 unmount 而重置,再进来的时候是新的

推荐使用 useState,如果这个局部本身比较大,涉及很多层组件,则推荐 constate

errorBoundary

Is your feature request related to a problem? Please describe.

Use format to recover from error is a bad idea. It should be a new hook.

Describe the solution you'd like

load('user', fetchMaybeWithAnError, {
  format: formatMaybeWithAnError,
  errorBoundary: (error, snapshot) => ...
})

Describe alternatives you've considered

Is errorBoundary a proper api name?

Additional context

/

region-signal

Is your feature request related to a problem? Please describe.

basic

import {createSignal} from 'region-signal';

const signal = createSignal<string>('initialValue');

const handleChange = e => {
    signal.value = e.target.value;
};

const Component = () => {
    return <input value={signal.value} onChange={handleChange} />;
};

async

import {createSignal} from 'region-signal';

const signal = createSignal<User>();

const loadUser = signal.loadBy(asyncFuncion);

// call loadUser in application lifecycle
loadUser({userId: 1});

const Component = () => {
    const value = signal.value;
    const loading = signal.loading;
    const error = signal.error;

    // ...
    return <div>{value}</div>;
}

Describe the solution you'd like
/

Describe alternatives you've considered
/

Additional context
/

Log error when error occurs and captured

Describe the bug
When error occurs and captured, there is no way to see it in console except enableLog: true.
But enableLog: true is an option, it is confused.

To Reproduce
Any error occurs.

Expected behavior
Always.

Screenshots
/

Desktop
Always.

Additional context
/

set with function

Is your feature request related to a problem? Please describe.
follow React.useState

Describe the solution you'd like

region.set(count => count + 1);

Describe alternatives you've considered
/

Additional context
/

Introduce load(..., { id }) in docs

  • implement region.loadBy(..., { id: (params) => params.join('-')})

  • add test cases

  • add a flag to switch id when load start

  • add docs

  • add examples

addReducer && reduce

Is your feature request related to a problem? Please describe.
Reducer is still a good design. It is powerful than set & format

Describe the solution you'd like

const reducer = (state, action) => state;
const region = new Region({
  reducers: {
    user: reducer
  }
})
// or
region.addReducer('user', reducer);
// Also consider named injectReducer

region.reduce('user', action);
// Also consider named as dispatch. Not really like it

Describe alternatives you've considered
/

Additional context
/

loadBy type inference

Is your feature request related to a problem? Please describe.
show ts type error when asyncFunction don't return correct result, and let user apply a reducer

Describe the solution you'd like
A simple implement

Describe alternatives you've considered
/

Additional context
/

useId

Is your feature request related to a problem? Please describe.
It may be helpful to implement useId

Describe the solution you'd like
/

Describe alternatives you've considered
/

Additional context
/

Return asyncFuncion response after I call region.loadBy

Describe the solution you'd like

Maybe, I want to use asyncFuncion response when I call region.loadBy. For example:

import {createRegion} from 'region-core';
import {useEffect} from 'react'
const region = createRegion<User>();
const loadUser = region.loadBy(asyncFuncion);

const Component = () => {
    const value = region.useValue();
    useEffect(() => {
        const fn = async () => {
            const response = await loadUser({userId: 1});
            // I want to use the response here
        }
        fn()
    }, [])
    return <div>...</div>;
}

I have the insterest to achieve this. 😉

[Umbrella] Plan to release 9.0.0

Normalize (optional)

  • try query-shape

  • maybe a hook help developer pick and memoize entities note: as id

TS (optional)

  • develop a pattern to write in form of wrapFunction

APIs

  • unstable_effect #10 note: removed

  • load with id

  • set with function region.set(count => count + 1) #16

  • rename apis to createRegion, createLocalStorageRegion

  • another callback like format called reducer

Deps

  • reimplement redux

Docs

  • rewrite document entirely

Surrounding Packages

  • extract region-throttle__note: abandoned__

  • release region-localStorage note: as createLocalStorageRegion

  • release region-entity note: as createRegion

  • extract region-react (maybe after 9.0.0)note: abandoned

What we will (not) do

Discuss what we will never do in this package here:

Apis to meet business

Such as normalize.

What redux / mobx / recoil / swr does

Just use them alone with region-core. You don't need to choose.

[Umbrella] Plan to release 10.0.0

Normalize with loadBy

  • loadBy with id as a selector

  • publish normalize practice(as swr)

TypeScript

  • generics for createRegion

Current Mode

  • useSuspense and other current mode api

combinedRegion.getProps() returns all the value

Is your feature request related to a problem? Please describe.
There isn't a easy way to get all the values of a combinedRegion.

Describe the solution you'd like

combinedRegion.set('a', 1);
combinedRegion.set('b', 2);
combinedRegion.getProps(); // { a:1, b:2, ... }

Describe alternatives you've considered
/

Additional context
/

[Umbrella] Plan to release 8.0.0

infrastructure

  • Typescript

    Done #2 , strict type inspection will be added during long-term development

  • enable Typescript strict

  • export d.ts

  • rollup (Typescript is enough for now)

  • try reskript (Typescript is enough for now)

flexible boundary of redux

  • remove dependencies of react-redux

  • each region create its own store (prevent unnecessary rendering)

fp (optional)

  • optimize setBy & loadBy

  • discuss whether it is called setBy & loadBy (it is now)

Surrounding Package (optional)

  • update region-form (still connect but worked well)

  • release region-request, tracked in #11 with region-entity(maybe)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.