状态管理API

状态是数据的变化,状态管理既是对数据的变化的管理。

在 src/models 下存在 dva model 文件,状态管理API才可以使用。

例如在以下目录结构中,useAuth.ts 是一个 dva model 文件。

├── models
│   ├── useAuth.ts

useAuth.ts 文件内容如下所示:

import { query } from '@/services/api';
import type { DvaModel } from 'alita';
 
export interface UseAuthModelState {
  name: string;
  sex: string;
}
 
const UseAuthModel: DvaModel<UseAuthModelState> = {
  namespace: 'useAuth',
 
  state: {
    name: '张三',
    sex: '男',
 
  },
 
  effects: {
    *queryName({ payload }, { call, put }): any {
      const data = yield call(query, payload);
      yield put({
        type: 'save',
        payload: { name: data.text },
      });
    },
  },
  reducers: {
    save(state, action) {
      return {
        ...state,
        ...action.payload,
      };
    },
  },
};
 
export default UseAuthModel;

connect

其作用是将 model 和 组件连接起来,同时被 connect 的 组件会自动在 props 中拥有 dispatch 方法。

connect 是一个函数,返回一个 React 容器组件,也是个函数,其参数是一个要和 model 连接的组件,连接后就可以把 model 中的 state 数据添加到组件的 props 中。

connect 的参数是一个函数,其参数是一个对象,包含 model 中所有的 state,示例如下:

{
  "useAuth": {
    "name": "张三",
    "sex": "男"
  },
}

其键值是每个 model 中的 namespace 的值,若没有设置 namespace ,则为 model 的文件名。

该函数会返回一个对象,该对象会添加到要和 model 连接的组件的 props 中。

示例:

import { connect } from 'alita';
import type { FC } from 'react';
 
const Foo: FC = (props) => {
  console.log(props);
  /** props
   * {
      dispatch: f(),
      "name": "张三",
      "sex": "男"
    }
  */
  return (
    <div>Foo</div>
  )
}
 
export default connect((state) => {
  return state.useAuth;
})(Foo);

useSelector

在不使用 connect 连接 model 和组件的情况下,也能获取到 model 中的 state。

useSelector 的参数是一个函数,其参数是是一个对象,包含 model 中所有的 state,示例如下:

{
  "useAuth": {
    "name": "张三",
    "sex": "男"
  },
}

其键值是每个 model 中的 namespace 的值,若没有设置 namespace ,则为 model 的文件名。

可以对 state 进行查找、筛选、处理后获得一个或者多个派生的 state。

而且每次 state 有更新,useSelector 会重新计算一次,返回新的结果,并重新渲染当前组件。

import { useSelector } from 'alita';
import type { FC } from 'react';
 
const Foo: FC = () => {
  const state = useSelector((state: any) => {
    return state.useAuth
  })
  return (
    <div>{state.name}</div>
  )
}
 
export default Foo;

useDispatch

在不使用 connect 连接 model 和组件的情况下,也能使用useDispatch 获取到 dispatch

import { useDispatch } from 'alita';
import type { FC } from 'react';
 
const Foo: FC = () => {
  const dispatch = useDispatch();
  const useAuth = useSelector((state: any) => {
    return state.useAuth
  })
  return (
    <div
      onClick={() =>{
        dispatch({
          type: 'useAuth/save',
          payload: {
            name: '王五',
          },
        });
      }}
    >{useAuth.name}</div>
  )
}
 
export default Foo;

useStore

用来获取底层的 Store 方法:

  • getState()

getState() 只会获得当前时刻的 state,而且state 更新后,getState() 不会再次调用,从而组件不会被重新选项,如下所示,点击【张三】,不会变成【王五】。

import { useDispatch, useStore } from 'alita';
import type { FC } from 'react';
 
const Foo: FC = () => {
  const dispatch = useDispatch();
  const store = useStore();
  const state = store.getState();
  const { useAuth } = state;
  return (
    <div
      onClick={() => {
        dispatch({
          type: 'useAuth/save',
          payload: {
            name: '王五',
          },
        });
      }}
    >{useAuth.name}</div>
  )
}
 
export default Foo;
  • dispatch(action)
import { useStore, useSelector } from 'alita';
import type { FC } from 'react';
 
const Foo: FC = () => {
  const store = useStore();
  const useAuth = useSelector((state: any) => {
    return state.useAuth
  })
  return (
    <div
      onClick={() => {
        store.dispatch({
          type: 'useAuth/save',
          payload: {
            name: '王五',
          },
        });
      }}
    >{useAuth.name}</div>
  )
}
 
export default Foo;
  • subscribe(listener)

添加一个变化监听器,每当 dispatch 的时候就会执行,可以在监听器中使用 getState() 获得当前 state。

import { useStore } from 'alita';
import { useState } from 'react';
import type { FC } from 'react';
 
const Foo: FC = () => {
  const store = useStore();
  const state = store.getState();
  const { useAuth } = state;
  const [name, setName] = useState(useAuth.name);
  const listener = () => {
    const state = store.getState();
    const { useAuth } = state;
    setName(useAuth.name)
  }
  store.subscribe(listener)
  return (
    <div
      onClick={() => {
        store.dispatch({
          type: 'useAuth/save',
          payload: {
            name: '王五',
          },
        });
      }}
    >{name}</div>
  )
}
 
export default Foo;
  • replaceReducer(nextReducer)

getDvaApp

获取 dva 实例。