Giter VIP home page Giter VIP logo

flooks's Introduction

Link in bio to widgets, your online home screen. ➫ 🔗 kee.so


flooks

State Manager for React Hooks, Auto Optimized

npm GitHub Workflow Status npm bundle size npm type definitions GitHub

English · 简体中文


Features

  • Gorgeous auto optimized re-render
  • Automatic request loading
  • Extremely simple API

Install

pnpm add flooks
# or
yarn add flooks
# or
npm i flooks

Usage

import create from 'flooks';

const useCounter = create((store) => ({
  count: 0,
  add() {
    const { count } = store();
    store({ count: count + 1 });
  },
  async addAsync() {
    await new Promise((resolve) => setTimeout(resolve, 1000));
    const { add } = store();
    add();
  },
}));

function Counter() {
  const { count, add, addAsync } = useCounter();

  return (
    <div>
      <p>{count}</p>
      <button onClick={add}>+</button>
      <button onClick={addAsync}>+~ {addAsync.loading && '...'}</button>
    </div>
  );
}

* Automatic request loading - if a function is async, asyncFn.loading is its loading state. If asyncFn.loading is not used, no extra re-render.

Demo

Edit flooks

Auto optimization

flooks realizes a gorgeous auto optimization, only actually used data will be injected into the component, re-render completely on demand, when React is truly "react".

Why flooks over zustand?

// zustand, need a selector
const { nuts, honey } = useStore((state) => ({
  nuts: state.nuts,
  honey: state.honey,
}));

// flooks, not need a selector
// but also only `nuts` or `honey` update trigger re-render, it's automatic
const { nuts, honey } = useStore();

Only functions, no re-render

const { a } = useStore(); // A component, update `a`
const { fn } = useStore(); // B component, only functions, no re-render

No updated state, no re-render

const { a } = useStore(); // A component, update `a`
const { b } = useStore(); // B component, no `a`, no re-render

No fn.loading, no extra re-render

const { asyncFn } = useStore(); // A component, call `asyncFn`
asyncFn(); // No `asyncFn.loading`, no extra re-render

// With normal loading solutions, even `asyncFn.loading` is not used,
// it will re-render at least twice (turn `true` then `false`).

API

create()

import create from 'flooks';

const useStore = create((store) => obj);

// For `react<=17`, you can use `create.config()` to pass
// `ReactDOM.unstable_batchedUpdates` for batch updating in async updates.
//
// create.config({ batch: ReactDOM.unstable_batchedUpdates }); // at app entry

store()

import create from 'flooks';

const useStore = create((store) => ({
  fn() {
    const { a, b } = store(); // get state

    store({ a: a + b }); // update state by data
    // or
    store((state) => ({ a: state.a + state.b })); // update state by function
  },
}));

License

MIT License (c) nanxiaobei

flooks's People

Contributors

dependabot[bot] avatar ironxc avatar nanxiaobei 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  avatar  avatar  avatar  avatar  avatar

flooks's Issues

有考虑加入“计算状态”的功能计划吗

通过掘金博客下的评论得知flooks宝库,极简的设计和性能很惊讶。
基于现有的实现方案总觉得不够优雅,感觉既然所属flooks模块就应该跟随模块,这样也方便维护和编码。
考虑计算状态的情况主要有以下几点:
1.针对模块state的衍生数据其实还是很常见,例如:转换、避敏、过滤等可能涉及到的操作。
2.利用flooks的性能优化点能够很好地缓存和使用,防止无效渲染。
当前能够达到计算状态相同效果的做法:
1.计算状态当做常规state存储,针对其依赖state被改变时同时改变计算状态。但是会显示不够优雅,显得不是很有意义。如果涉及其他异步操作等不方便组织代码。
2.useMemo,同等效果情况下非模块内数据,切换组件不具备缓存效果,且不方便多组件共享。
如果可行粗略的几点功能设计建议:
1.默认深度依赖,自动识别依赖项。
2.计算状态的申明还是采取函数式,为了区分actions可以导出一个API传入计算函数。
3.支持异步操作,初始化执行。
4.可识别其他模块所依赖依赖state

请教:是否更推荐model数据细粒度化?

作者你好,
感谢提供了如此简便的状态管理方式,有个疑问请教一下
阅读了一下源码,如果同一个model中state的数据不只一个,调用actions是无差别触发setState,这和react的context是一样的。
如果需要避免这种不必要的更新,可能需要细粒度的写model。这样在共用state较多的情况下,应该如何组织代码 ?
在假设细粒度成立的条件下,model数量将大大增加,不引入模块化的模块化的概念就变得很难管理了,当然也可以在开发者间写name的时候形成默契namespace。

总结一下,主要疑问是:
1、flook是否更适合细粒度的全局状态管理 ?
2、是否有在flooks中引入模块化概念的打算 ?

直接 对对象的数据进行操作,更新有延迟

const useStore = create(({ get, set }) => ({
  count: 0,
  result: {
    hello: {
      sum: 0
    }
  },
  add() {
    const { count } = get();
    set({ count: count + 1 });
  },
  async addAsync() {
    await new Promise((resolve) => setTimeout(resolve, 1000));
    const { add } = get();
    add();
  },
  updateData() {
    const { count, result } = get();
    // 方式1 不可以, 更新会有延迟, 需要等待 其它的参数更新后才更新这个参数
    result.hello.sum++;
    // result.hello.sum = result.hello.sum + 1;
    // result.hello.sum = "hello";
    set({ result });
    // 方式2 可以
    // set({ result: { ...result } });
    // 方式3 可以
    // const data2 = { hello: { sum: "update" } };
    // set({ result: data2 });
    // 方式4 可以
    // set({ result: { hello: { sum: "update" } } });
  }
}));

https://codesandbox.io/s/clever-dhawan-zd8ipo?file=/src/App.js:0-2680

BugDemo

看例子:
Edit flooks

import useModel from 'flooks';
import { useEffect } from 'react';

const store = ({ get, set }) => ({
  label: '6666666666',
  setLabel(str) {
    set({ label: str });
  },
});

const SubView = () => {
  const { setLabel } = useModel(store);

  useEffect(() => {
    console.log('change label to 77777777');
    setLabel('77777777');
  });

  return (
    <div>
      <h2>SubView</h2>
      Here change the label to 77777777.
    </div>
  );
};

const BugDemo = () => {
  const { label } = useModel(store);

  return (
    <div>
      <h2>BugDemo</h2>
      label: {label}
      <br />
      <br />
      <br />
      <SubView />
    </div>
  );
};

export default BugDemo;

父子组件引用同一个store,子组件初始化时更新store数据,更新的数据不会同步到父组件。

因为子组件更新数据时,父组件还没执行到这一行: modelSubs.push(updater); 导致父组件的 updater 没被执行到。

useModel 里的那个 useEffect 是在子组件的 useEffect 之后执行的,也就是说 useModel 在初始化过程中(由子组件)变更的数据不会响应到当前 useModel 的组件,因为 updater 还没初始化完毕。

在基于route 做了 code splitting 的项目使用会出问题

其实更准确的描述是,

useModel这个方法依赖于在这之前已经setModel过,

比如我在 路由 /couter模块中使用了useModel('home'),但是setModel('Home')声明在/home

直接访问/couter就会出错,因为这时候/home还没有挂载,感觉这样的话还是要在顶层容器中集中遍历setModel下?这样就不是去中心化了,作者有没有考虑这方面怎么解决呢?因为在实际项目中, 基于路由的代码分割还是挺常见的

Create a .npmignore

It would be good to also include a .npmignore file so that you don't publish files that only exist in your dev environment and don't need to be published.
here are some things that shouldn't be published:

  • your .babelrc
  • prettier.config.js
  • your logo probably as people likely won't open it from their node_modules fetc
  • etc

Here's some documentation about it:
The npmignore file

Also note that you'll need to duplicate the contents of your .gitignore if you want those rules to be respected as the .npmignore will override your gitignore (only when publishing on npm, not in general).

Thanks for reading my issue, good luck on your project

建议

建议将actions和state的使用分开,或者标记setter, 用一个useModel的时候会出现一个只使用了action的组件,在setState的时候也就是setters遍历运行时会重新渲染

性能

Uncaught Invariant Violation: Too many re-renders. React limits the number of renders to prevent an infinite loop.

在react 18 中 报错Missing getServerSnapshot, which is required for server-rendered content. Will revert to client rendering.

Missing getServerSnapshot, which is required for server-rendered content. Will revert to client rendering.

//version

"flooks": "^6.1.0",
"next": "12.2.3",
"react": "18.2.0",
"react-dom": "18.2.0",

//flooks

import create from 'flooks';

const useCustomer = create((store) => ({
    error: "",
}));

export default useCustomer;

//login.js

import useCustomer from "@/models/customer/model";

const Login = () => {
    const { error } = useCustomer();

    return (
        <div>
             {error}
        </div>
    )
}

image

store的类型定义可以完善一下嘛

// 这里是自己定义的type
type MyStoreType = ReturnType<typeof myStore>;
const myStore = (store: ???这里好像没法自己定义type,希望提供内置type ) => ({
  myFunction() {
    // 这里得用自己定义的type,否则左边拿到的都是any类型
    const { ??? } = store() as MyStoreType;
  }
});
const useMyStore = create(myStore);

在React Native环境下使用会出现Navigator重置的现象

你好,我非常喜欢你对redux理解和这个flooks库。
但是最近我想将flooks应用在React Native上,因为 我知道redux在React和React Native上使用的库是一样的,我想当然的认为flooks应该也差不多。
但是当我使用后发现当我在跳转到某个路由下使用useModel拿到action然后使用action修改state时发现我的navigator被重置到初始状态了,就是跳到了路由设置的默认页面。
之后我尝试使用redux写了个demo,发现redux dispatch action改变state时不会重置路由。
所以想请教一下对于这个问题有什么思路吗?如果对RN不感兴趣的话能否给点提示以便我对源码进行修改。谢谢

我测试的环境:

"dependencies": {
    "flooks": "^1.2.0",
    "react": "16.9.0",
    "react-native": "0.61.5",
    "react-native-gesture-handler": "^1.5.1",
    "react-native-reanimated": "^1.4.0",
    "react-native-screens": "^2.0.0-alpha.13",
    "react-native-vector-icons": "^6.6.0",
    "react-navigation": "^4.0.10",
    "react-navigation-stack": "^1.10.3",
    "react-navigation-tabs": "^2.6.0"
  },

系统:macOS Mojave
IDE: vs code
RN版本:react-native-cli: 2.0.1

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.