Skip to content
React Hooks based, concise, lightweight framework.
JavaScript
Branch: master
Clone or download
jilin.jin
jilin.jin change example
Latest commit 61c58ed Aug 9, 2019
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
src fix bugs of connect && useAdd Aug 7, 2019
.gitignore remove example Aug 9, 2019
CHANGELOG.md optimized Aug 8, 2019
CODE_OF_CONDUCT.md Create CODE_OF_CONDUCT.md Aug 6, 2019
CONTRIBUTING.md Create CONTRIBUTING.md Aug 6, 2019
LICENSE add license Aug 4, 2019
README.md change example Aug 9, 2019
package.json change example Aug 9, 2019

README.md

dva-react-hook

NPM size

React Hooks based, concise、lightweight framework.

Table of Contents

Install

# Yarn
yarn add dva-react-hook

# NPM
npm install --save dva-react-hook

In Node.js

var dvaHook = require('dva-react-hook');

Quick Start

//
// Bootstrap your app
//
import React from 'react';
import Provider from 'dva-react-hook';

const initState = {
  name:'Lynn',
  apples:{
      state:'raw',
      count:4
  }
}

ReactDOM.render(
  <Provider {...initState}>
    <App />
  </Provider>,
  document.getElementById('root'),
);
//
// Individual components
//
import React from 'react';
import { useModel } from 'dva-react-hook';

export default function Counter(){
    const [ { value: name } ] = useModel('name');
    const [ { value: count }, setCount ] = useModel('apples/count');

    const eat = () => {
        setCount(count - 1)
    }

    return <div>
        <span> { name } has { count } apples</span>
        <button onClick={eat}>Eat One</button>
    </div>    
}

Usage

NOTE: React hooks require react and react-dom version 16.8.0 or higher.

Provider

The Provider component provides state and dispatch for subcomponents, so it's best to put the Provider component at the top level.

You can pass props to Provider, the props will be initialized into state

ps: the state initialized by props can only be changed using the function returned by useModel
  const initState = { count: 0 }
  <Provider {...initState}>
    <App />
  </Provider>

Dynamic

The Dynamic component is the only entry for registering effects for each model, you can do this in synchronous or asynchronous.

Props Type Description
renderBefore Function you can something before render
component React.ReactNode A React component to render
render Function This allows for convenient inline rendering and wrapping,in addition to the ability to load component with ’import‘ asynchronously
models Function | Array Function should return an array.You can load model asynchronously with ’import‘ or synchronously with array
import { Dynamic } from 'dva-react-hook';


<Dynamic component={ReactNode} />
<Dynamic render={() => <App />} />
<Dynamic render={() => import('url')} />
<Dynamic models={() => [import('url1'),import('url2'),...]} />
<Dynamic models={[model-object,model-object,...] />
model-object format:
{
    name:'some-name',
    init: Function | Object | Number | Array | ..., //optional --default value is {}
    effects:{
      fetch: async({state:{value},setState,select}) => {
      }
    }
}

useModel

You can use useModel hook to inject a model state into a component. The only argument to the useModel() Hook is state path. It returns a pair of values: an object and a function that updates the model state. The object returned has a getter named value, value returns the current model state defined by the path. You can take the value when you define it, or take the value until you use it. The difference is that when you take the second action, you will get the updated value synchronously before the component re-renders. It is not recommended to do this unless it is absolutely necessary.

import { useModel } from 'dva-react-hook';


const [ user, setUser ] = useModel('user');
const [ { value: total } ] = useModel('list/total');
const [ { value: page }, setPage ] = useModel('list/page');
const click = () => {
  setUser('dva-hook');
  user.value // the value is dva-hook
  setPage(1)
  page // the value is not 1
}
ps: Usually when a context value is changed, all components that useContext will re-render, but this framework is unusual, so if only used part of the state is changed, the corresponding component will re-render.

useDispatch

useDispatch returns the function you registered in a model effects,the only argument to the useDispatch() Hook is an object, the object must have an property named type, also you can set some other properties. The function returned by useDispatch is wrapped by an async function and also is injected with an object parameter,so that you can get the state of the model、the function updates it and a selector which can select other models' state and set other models' state.

//if your model is like this
{
  name:'login',
  init:{
    name:null,
    age:null,
  },
  effects:{
    // Defining an async function is recommended, but it is not required
    async login({name,pass},{state,setState,select}){

      // state: state.value is the state of login
      // setState: function updates the login state, not partly
      // select: its usage is as same as useModel

      //ps: when the login function is called like the this ( you dont pass any argument to it ) -- loginaction() in your component, You can't write any other parameters except the parameters being injected

      //so your code may like this:  async login({state,setState,select}){}
    }
  }
}

// you may in your component write these

const loginaction = useDispatch({ type:'login/login', otherproperties:''});
//otherproperty is optional, if you set some other properties, you can get them in the injected argument

//so your code maybe like this   async login({name,pass},{state,setState,select, otherproperties }){}



loginaction({name,pass}).then(data => {
  // do something
}).catch(error => {
  // do something
}).finally(() => {
  // do something
})

connect

If you are obsessed with writing classes and have no other state management tools, I provide the connect decorator. The connect decorator receives two arguments: the first is required and the second is optional. The first argument is as same as useModel's. The second argument is as same as useDispatch's. In your class component,you will have three new props: hookState、setHookState、dispatch.

import { connect } from 'dva-react-hook';

@connect('list/page',{ type: 'list/fetch' })

class Demo extends React.Component{
  componentDidMount(){
    const page  = this.props.hookState;
    this.props.dispatch(page);
  }
  render(){
    return <div>
      <span>{this.props.hookState}</span>
      <div><Table /></div>
    </div>
  }
}
ps: each class component can only be injected by one props and one dispatch. This is entirely due to the single responsibility principle to make the components as clear and easy to understand as possible.

useAdd

If you want to dynamically inject model state, you can use it. useAdd has three arguments: name initdata, once

import { useAdd } from 'dva-react-hook';

useAdd(name, initdate, once)
// name is the model's name
// initdata can be an object or function
// once decided whether to execute only once just like componentDidMount

Example

License

MIT © Facebook Inc.

You can’t perform that action at this time.