Code Monkey home page Code Monkey logo

royjs's Introduction

Roy buildStatus

A powerful mvvm framework for react.

Install

npm install @royjs/core --save

Motive

image

The state management is nothing more than changing the state from partial to partial sharing, so in an application, each component can be managed corresponding to a state, and only when this part needs to be shared, it is extracted.

Usage

Basic Usage

import {Store, inject} from '@royjs/core';

const store = new Store({
    state: {
        count: 0
    },
    actions: {
        add(state, payload) {
            state.count++;
        },
        reduce(state, payload) {
            state.count--;
        }
    }
});

@inject(store)
class App extends React.Component {
    render() {
        const {count} = this.props.state;
        return <div onClick={() => this.props.dispatch('add')}>{count}</div>
    }
}

Centralized Store

import {Store, connect} from '@royjs/core';

const store = new Store({}, {
    plugins: [devtools]
});

store.create('module1', {
    state: {
        name: 'module1'
    },
    actions: {
        change(state, payload){
            state.name = payload;
        }
    }
});

store.create('module2', {
    state: {
        name: 'module2'
    },
    actions: {
        change(state, payload){
            state.name = payload;
        }
    }
});

@connect(state => state.module1)
class App extends React.Component {
    onClick = () => {
        this.props.dispatch('module2.change', 'changed name from module1');
    }
    render() {
        return <div onClick={this.onClick}>{this.props.name}</div>
    }
}

@connect(state => state.module2)
class App2 extends React.Component {
    render() {
        return <div>{this.props.name}</div>
    }
}

Merge localStore to globalStore

import {Store, inject, connect} from '@royjs/core';

const store = new Store();

const subModuleStore = new Store({
    state: {
        name: 'subModule'
    },
    actions: {
        change(state) {
            state.name = 'subModuleChanged';
        }
    }
})
@inject(subModuleStore)
class SubModule extends React.Component {
    render() {
        return <div onClick={() => this.props.dispatch('change')}>{this.props.state.name}</div>
    }
}

store.mount('subModule', subModuleStore);

@connect(state => state.subModule)
class App extends React.Component {
    render() {
        return <div>{this.props.name}</div>
    }
}

Async Request

import {Store, inject} from '@royjs/core';

const store = new Store({
    state: {
        count: 0
    },
    actions: {
        add(state, payload) {
            state.count++;
        },
        reduce(state, payload) {
            state.count--;
        },
        fetch(state, payload) {
            this.request('./url').then(ret => {
                state.dataSource = ret.ds;
            });
        }
    }
});

@inject(store)
class App extends React.Component {
    componentDidMount() {
        this.props.dispatch('fetch');
    }
    render() {
        const {dataSource} = this.props.state;
        return <div onClick={() => this.props.dispatch('add')}>{dataSource}</div>
    }
}

Benchmark

Test on my macbook pro (Intel Core i7 2.2GHz)

benchmark

tnpm run benchmark

royjs's People

Contributors

chenzhongchen27 avatar windygex 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

Watchers

 avatar  avatar

royjs's Issues

inject API中访问state的方式修改

背景

inject API一直是这样的使用方式, Royjs通过篡改App的原型链达到了使用this.store访问store中数据的目的。

@inject(store)
class App extends React.Component {
    render() {
      const state = this.store.state
   }
}

但是存在下面的问题点

  1. 对于App而言,如果我想通过inject生成多个组件,则只会最后一个store的改变会影响组件

    class App extends React.Component {
        render() {
            const state = this.store.state;
        }
    }
    
    const StoreApp = inject(store)(App)
    const ListStoreApp = inject(listStore)(App)

    上面的代码只有listStore数据的改变才会影响到视图的刷新,所以期望将inject的方式修改成下面

  2. 无论是connect还是inject都可以通过this.props.dispatch的方式调用action, 进行语法分析更容易。

实施方案

通过this.props.statethis.props.dispatch来代替this.store.statethis.store.dispatch

class App extends React.Component {
    render() {
        const state = this.props.state;
    }
}

const StoreApp = inject(store)(App)
const ListStoreApp = inject(listStore)(App)

支持 class 模式的 store

期望的方式 如下:

export default class Store extends App.Store {
  namespace = 'substore'

  state = {
    width: null,
    showError: false,
    list: [],
    ready: false
  }

  @loading('loading') // 表示 state.set('loading', true) -> state.set('loading', false)
  async search (state) {
    try {
      const data = await this.service.getList()
      // 效果同 state.set()
      this.state.set('list', data)
    } catch (err) {
      console.error(err)
    }
  }

  changeWidth (state, { width }) {
    state.set('width', width);
  }

  triggerError (state) {
    state.set('showError', true);
  }

  async init (state) {
    setTimeout(() => {
      this.dispatch('search');
      state.set('ready', true)
    }, 1000);
  }

  back () {
    // TODO
  }
}

优势:

  1. 能提供完整的 TS 支持,同时也能支持 decorator
  2. 支持 namespace,当多个 store 合并时,可以通过类似 store.{namespace} 的方式访问子 store

connect API 优化

connect的API参照了redux的实现,但是较为繁琐,计划提供下面的快捷方式

    connect({
        state: ['a','b', {
            'c': 'a.b'
        }]
        actions: ['onPut','onAdd', {
            onModify: 'onModifyById'
        }]
    }, {
        pure: true,
        inject: true
    })

针对对象取值的优化

当前对象取值将.作为特殊的分隔符导致使用文件路径作为key的无法获取到正确的值

const b = {};
b['/src/a.js']

插件机制的优化

当前store的插件是在constructor里面运行的,对于后注册的子store无法进行扩展.

异步请求支持只变更最后一次

for example:

fetchUser: [function* fetchUser({ payload }, { call, put, select }) {
      const { res } = yield call(queryUser, payload);
      const data = res.data
      yield put({
        type: 'setUser',
        payload: data
      });
      return data;
    }, { type: 'takeLatest' }]

useStore 在组件被 unmount 之后还会触发 setState

目前使用 useStore 时,如果在 useEffect 里做了 dispatch,当组件被 unmount 之后仍然会在内部 setState,导致 react warning

image

我看了 useStore 的内部实现,对事件进行 unsubscribe 的,但实际依然会有这个问题,这块实现得看下:

image

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.