Giter Site home page Giter Site logo

sl1673495 / react-composition-api Goto Github PK

View Code? Open in Web Editor NEW
88.0 3.0 7.0 3.49 MB

:art: Simple React state management. Made with @vue/reactivity and ❤️.

License: MIT License

TypeScript 100.00%
reactivity react state state-management vue3 react-vue react-setup reactive-programming es6-proxy react-state

react-composition-api's Introduction

Welcome to rxv 👋

Version Documentation License: MIT

Use Vue3 Composition Api in React to manage state, just import @vue/reactivity, rxv means React x Vue

本项目为学习性质,不建议用于生产环境!

Demo

rxv

在 React 应用中使用@vue/reactivity 中的所有响应式能力

  1. 使用 setup 在组件中体验 Vue-Composition-Api
  2. 使用极简的 api 实现全局状态管理

Docs

https://sl1673495.github.io/react-composition-api

Why

  1. 直接引入@vue/reacivity,完全使用 Vue3 的 reactivity 能力,拥有computed, effect等各种能力,并且对于SetMap也提供了响应式的能力。 后续也会随着这个库的更新变得更加完善的和强大。
  2. vue-next仓库内部完整的测试用例。
  3. 完善的 TypeScript 类型支持。
  4. 完全复用@vue/reacivity实现超强的全局状态管理能力
  5. 状态管理中组件级别的精确更新。

Usage

npm i rxv -S
npm i @vue/reactivity -S

支持@vue/reactivity内部提供的所有 api,并在 React 组件中使用。

快速上手示例

store:

import { reactive } from "@vue/reactivity"

export const state = reactive({
  count: 0,
})

export const add = () => (state.count += 1)

export const store = reactive(state)

export type Store = typeof store

组件:

import React from "react"
import { Provider, useStore } from "rxv"
import { store, add, Store } from "./store"

function Count() {
  const countState = useStore((store: Store) => ({
    count: store.count,
  }))

  return (
    <Card hoverable style={{ marginBottom: 24 }}>
      <h1>计数器</h1>
      <div className="chunk">
        <div className="text-chunk">
          store中的count现在是 {countState.count}
        </div>
        <Button onClick={add}>add</Button>
      </div>
    </Card>
  )
}

export default () => {
  return (
    <Provider value={store}>
      <div className="flex">
        <Count />
      </div>
    </Provider>
  )
}

相对复杂的示例

这个例子里使用了 Vue3 中的 computedeffect 等能力,是一个相对比较复杂的示例。

// store.ts
import { reactive, computed, effect } from "@vue/reactivity"

export const state = reactive({
  count: 0,
})

const plusOne = computed(() => state.count + 1)

effect(() => {
  console.log("plusOne changed: ", plusOne)
})

const add = () => (state.count += 1)

export const mutations = {
  // mutation
  add,
}

export const store = {
  state,
  computed: {
    plusOne,
  },
}

export type Store = typeof store
// Index.tsx
import { Provider, useStore } from "rxv"
function Count() {
  const countState = useStore((store: Store) => {
    const { state, computed } = store
    const { count } = state
    const { plusOne } = computed

    return {
      count,
      plusOne,
    }
  })

  return (
    <Card hoverable style={{ marginBottom: 24 }}>
      <h1>计数器</h1>
      <div className="chunk">
        <div className="chunk">store中的count现在是 {countState.count}</div>
        <div className="chunk">
          computed值中的plusOne现在是 {countState.plusOne.value}
        </div>
        <Button onClick={mutations.add}>add</Button>
      </div>
    </Card>
  )
}

export default () => {
  return (
    <Provider value={store}>
      <Count />
    </Provider>
  )
}

可以看出来,store 的定义完全复用了@vue/reactivity中的能力,而不会引入额外的学习成本,并且里面的所有能力都可以完美支持。

具体的代码和效果可以看文档中的 复杂示例

支持的 Vue3 api

除了内置的几个 api 以外,其他所有的 api 都是 Vue 内部提供的。

具体支持的 api,可以看vue-next仓库中的导出的 api

export { ref, isRef, toRefs, Ref, UnwrapRef } from "./ref"
export {
  reactive,
  isReactive,
  readonly,
  isReadonly,
  shallowReadonly,
  toRaw,
  markReadonly,
  markNonReactive,
} from "./reactive"
export {
  computed,
  ComputedRef,
  WritableComputedRef,
  WritableComputedOptions,
  ComputedGetter,
  ComputedSetter,
} from "./computed"
export {
  effect,
  stop,
  pauseTracking,
  resumeTracking,
  ITERATE_KEY,
  ReactiveEffect,
  ReactiveEffectOptions,
  DebuggerEvent,
} from "./effect"
export { lock, unlock } from "./lock"
export { TrackOpTypes, TriggerOpTypes } from "./operations"

注意computedref这些包装后的值没有提供自动拆包的功能,必须用data.value去读取和赋值。

LICENSE

MIT

Author

👤 ssh

Show your support

Give a ⭐️ if this project helped you!


This README was generated with ❤️ by readme-md-generator

react-composition-api's People

Contributors

sl1673495 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

Watchers

 avatar  avatar  avatar

react-composition-api's Issues

rxv 最简实现

经过我长时间的使用,你的方案确实不错,但是还有更简的写法,没必要写的如你这般复杂:

import { useEffect, useReducer } from "react";
import { effect, stop, ReactiveEffect } from '@vue/reactivity';

export function useReactiveState<T>(fn: () => T) {
  const [state, dispatch] = useReducer((state: T, action: T) => action, fn());
  useEffect(() => {
    const _effect = effect(fn, {
      lazy: true,
      scheduler: (job: ReactiveEffect<T>) => dispatch(job()),
    });
    dispatch(_effect());
    return () => stop(_effect);
  }, []);
  return state;
}

使用方式:

import { ref } from '@vue/reactivity';

const count = ref(0);

const App = () => {
  const num = useReactiveState(() => count.value);
  return <div>
    <button onClick={() => count.value++}>add 1</button>
    <p>{num}</p>
  </div>
}

这样就行了。

感谢提供rxv设计思路

非常感谢提供这样一种思路,已被使用在以下架构中:

虽然我没有直接使用您的rxv,但是还是非常感谢。不使用的原因是我需要定义useStoreuseContextState函数,同时之后将会稍微修改内部逻辑。该项目为公司内部架构,如果之后开源,那么我将会声明这块架构采用了您的架构。
再次感谢!

很多开发者都可能还没有意识到你的这种模式将会为react带来多大的便利,我相信这是一种很好的思路。对于小白而言,都不会懂的。

rxv:bug: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.

这是一个很容易复现的bug。我做了一个codesandbox项目,你可以看下:

codeSandBox

image

主要问题是在当我使用FC组件时候,动态切换组件会造成源组件引用还是会被更新,而源组件已经unmount状态了。不知道您有没有发现这个问题。

如果codesandbox无法查看,那么请前往 rxv-bug 这个项目查看。

$ git clone [email protected]:cevio/rxv-bug.git
$ cd rxv-bug
$ npm start

3秒后打开console可以看到错误。

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.