Dva: 如何清空 redux 信息?

Created on 11 May 2017  ·  16Comments  ·  Source: dvajs/dva

例如 redux-reset

如何清空 redux 的信息?


使用场景:

一个人员管理多个校区,每个校区的信息不通,切换校区时候,为了避免旧数据造成的问题,只好使用 location.reload() 强制页面刷新以便更新全部内存信息。
想要做到在不刷新页面的清空下,清空 redux 的数据?

Most helpful comment

dva-reset-state 一个插件,直接拿过来用,大家可以参考下

All 16 comments

我想到一种办法,写一个公用方法,取消注册model,app.unmodel(namespace),再注册回去app.model(model)

写一个专门的reducer去清?

@xufei 飞姐,借道问下,dva为什么好久没更新了,在憋大招吗?

实际业务中,很多model带有初始state的,单纯的清空state中的数据对象容易出现问题.
我们的做法是,创建model的时候,将model的初始state 克隆一份,然后默认给每个model都添加resetState reducer(reset方法中会将克隆的初始数据 更新到state中),需要清理的时候,只需发送对应action即可 ( xxx/resetState ).
但是如果是全局reset,也还是比较蛋疼,只能每个model都发一个action,不过暂时还没遇到这种需求.

感觉,不应该会出现这种现象吧。第一个校区的初始化信息,也应该是有 action 吧,切换校区,不应该是也调用这个 action 吗? 即使你全部重置了 state ,切换校区的时候 action 之后,不应该是自动就初始化好了吗?

@laketea @zjxpcyc @xufei 结合你们的意见,觉得也是还是得直接使用 action 来初始化数据才是。

每个 model 都增加个 reload 的方法,切换之后每个去清空。

@dicklwm 不知道 unmodel 会不会有后遗症。所以还是参考他们的做法直接让每个 model reload 重置数据。

谢谢大家。


不过,短期内我还是采用暴力方法直接 reload 页面。等找到更好的方法就补充回来。

如果确实是重置整个 state 那 @xufei 的方法是最简单的:

// const initialState = ...;
const app = dva({
  onReducer: reducer => {
    return (state, action) => {
      if (action.type === 'RESET') {
        return initialState;
      }
      return state;
    };
  }
});
// Usage
dispatch({ type: 'RESET' });

从网上搜过来,照着 @xufei 老大的代码搞了半天,就是跑不起来。花了半天才搞清楚状况,使用 onReducer 的时候除了要返回新的 state,还需要返回一个 routing 才行。参考了 dva/test/reducers-test.js 的代码

本人项目基于 antd-pro,需要在 src 目录下面新增两个文件 app.jsinitialState.js

首先,在 ./src/initialState.js 文件中定义初始状态。

import defaultSettings from './defaultSettings';

export default {
  setting: defaultSettings,
  loading: {
    effects: {},
  },
  global: {
    layout: 'basic', // Page layout switch (options: basic | map)
    collapsed: false,
    notices: [],
  },
  login: {
    status: false,
    authority: 'guest',
  },
  register: {
    status: false,
  },
}

然后,在 ./src/app.js 文件的 onReducer 钩子中判断,当 action.typeRESET 的时候重置 state 树。

import initialState from './initialState';

// eslint-disable-next-line
export const dva = {
  config: {
    initialState,
    onReducer(reducer) {
      return (state, action) => {
        const newState = action.type === 'RESET' ? initialState : reducer(state, action);
        return { ...newState, routing: newState.routing };
      };
    },
  },
};

这样定义好,在需要的地方(比如 logout)就可以直接使用,比如修改 antd-pro 顶部菜单 ./src/layouts/Header.js 的退出登录操作:

class HeaderView extends PureComponent {
  ...

   handleMenuClick = ({ key }) => {
    ...

    if (key === 'logout') {
      dispatch({ type: 'RESET' });
      dispatch({ type: 'login/logout' });
    }
  };

  ...
}

在应用开始的时候把初始state存下来,作为reset的数据是否可行

@laozhu

你好,我按照你写的,运行时报错:Uncaught (in promise) Could not find router reducer in state tree, it must be mounted under "router"

也就是 routing 这个在 initialState 对象中没有,这个应该是从哪里定义的?

@shangdev @laozhu dva 升级后出现这个了 index.js:1 uncaught at _callee Could not find router reducer in state tree, it must be mounted under "router"
代码是一样的

从网上搜过来,照着 @xufei 老大的代码搞了半天,就是跑不起来。花了半天才搞清楚状况,使用 onReducer 的时候除了要返回新的 state,还需要返回一个 routing 才行。参考了 dva/test/reducers-test.js 的代码

本人项目基于 antd-pro,需要在 src 目录下面新增两个文件 app.jsinitialState.js

首先,在 ./src/initialState.js 文件中定义初始状态。

import defaultSettings from './defaultSettings';

export default {
  setting: defaultSettings,
  loading: {
    effects: {},
  },
  global: {
    layout: 'basic', // Page layout switch (options: basic | map)
    collapsed: false,
    notices: [],
  },
  login: {
    status: false,
    authority: 'guest',
  },
  register: {
    status: false,
  },
}

然后,在 ./src/app.js 文件的 onReducer 钩子中判断,当 action.typeRESET 的时候重置 state 树。

import initialState from './initialState';

// eslint-disable-next-line
export const dva = {
  config: {
    initialState,
    onReducer(reducer) {
      return (state, action) => {
        const newState = action.type === 'RESET' ? initialState : reducer(state, action);
        return { ...newState, routing: newState.routing };
      };
    },
  },
};

这样定义好,在需要的地方(比如 logout)就可以直接使用,比如修改 antd-pro 顶部菜单 ./src/layouts/Header.js 的退出登录操作:

class HeaderView extends PureComponent {
  ...

   handleMenuClick = ({ key }) => {
    ...

    if (key === 'logout') {
      dispatch({ type: 'RESET' });
      dispatch({ type: 'login/logout' });
    }
  };

  ...
}

你这个有完整的代码吗?在app.js里面定义完dva后,在哪调用的或者说启动的呢?

@laozhu 可以去除initialState的定义,当action.typeRESET时,直接使用初始化的数据reducer({},{type:'@@INIT'})

export const dva = {
  config: {
    onReducer(reducer) {
      return (state, action) => {
        const newState = action.type === 'RESET' ? reducer({},{type:'@@INIT'}) : reducer(state, action);
        return { ...newState, routing: newState.routing };
      };
    },
  },
};

当需要重置所有的model时

class HeaderView extends PureComponent {
  ...

   handleMenuClick = ({ key }) => {
    ...

    if (key === 'logout') {
      dispatch({ type: 'RESET' });
      dispatch({ type: 'login/logout' });
    }
  };

  ...
}
  • 如果要重置某个namespace下的state直接dispatch 该state对应的reducer就行了。

  • 如果要重置某个namespace下的所有state

 onReducer(reducer) {
    let initialState: any = null;
    return (state: any, action: any) => {
      let newState: any = reducer(state, action);
      if (action.type === "@@INIT") {
        initialState = newState; //缓存所有初始state
      }

      const actionTypeArr: string[] = action.type.split("/");

      if (actionTypeArr.length === 1 && action.type === "reset") {
        newState = initialState;
      }

      if (actionTypeArr.length > 1) {
        const namespace = actionTypeArr[0];
        const postfix = actionTypeArr[actionTypeArr.length - 1];
        const modelState = initialState[namespace];
        if (postfix === "reset" && modelState) {
          newState = {
            ...newState,
            [namespace]: modelState
          }; //重置某个namespace的state,直接dispacth({type:"{namespace}/reset"})
        }
      }

      return newState;
    };
  }
  • 如果要重置某个namespace下的state直接dispatch 该state对应的reducer就行了。
  • 如果要重置某个namespace下的所有state
 onReducer(reducer) {
    let initialState: any = null;
    return (state: any, action: any) => {
      let newState: any = reducer(state, action);
      if (action.type === "@@INIT") {
        initialState = newState; //缓存所有初始state
      }

      const actionTypeArr: string[] = action.type.split("/");

      if (actionTypeArr.length === 1 && action.type === "reset") {
        newState = initialState;
      }

      if (actionTypeArr.length > 1) {
        const namespace = actionTypeArr[0];
        const postfix = actionTypeArr[actionTypeArr.length - 1];
        const modelState = initialState[namespace];
        if (postfix === "reset" && modelState) {
          newState = {
            ...newState,
            [namespace]: modelState
          }; //重置某个namespace的state,直接dispacth({type:"{namespace}/reset"})
        }
      }

      return newState;
    };
  }

action.type === "@@INIT"我改成action.type.indexOf('@@redux/INIT') === 0

dva-reset-state 一个插件,直接拿过来用,大家可以参考下

Was this page helpful?
0 / 5 - 0 ratings