使用redux-toolkit将状态重置为初始状态

85

我需要将当前状态重置为初始状态,但是我的所有尝试都失败了。我该如何使用Redux Toolkit实现它?

const showOnReviewSlice = createSlice({
  name: 'showOnReview',
  initialState: {
    returned: [],
  },
  reducers: {
    reset(state) {
      //here I need to reset state of current slice
    },
  },
});


1
@AjeetShah 的解决方案非常完美,感谢您的分享。 - Guilherme Samuel
9个回答

149

像这样:

const intialState = {
  returned: []
}

const showOnReviewSlice = createSlice({
    name: 'showOnReview',
    initialState,
    reducers: {
        reset: () => initialState
    }
});

8
可以,它有效。另外,reset() {return initialState} 或 reset: () => initialState 也是正确的写法。 - Zireael
16
我原以为只需将 state = initialState 设定即可,因为在其他例子中,我们只需要变更 state。可惜,重置状态需要采用不同的方法 :/ - Dorklord
6
我必须承认,即使redux-toolkit很棒,它仍然有一点不可变性的黑魔法:D 顺便说一句,return { ...initialState } 也可以使用... - Baterka
5
state = initialState 这样写是无法起作用的,因为你改变了引用,而 Redux Toolkit 无法察觉到这一点,它仍然持有旧的引用。你必须通过修改原始的 state 或者 返回 新对象来实现更新。 - Qwerty
2
@Baterka return { ...initialState } 是不必要的,也许你来自传统的redux,那里禁止了突变。在这里,return initialStatereturn { ...initialState } 是等价的。 - Qwerty
显示剩余4条评论

18

当使用多个切片时,可以使用 extraReducers 将所有切片恢复到其初始状态。

首先,创建一个可供所有切片使用的操作:

export const revertAll = createAction('REVERT_ALL')

在每个切片中添加initialStateextraReducers reducer,使用revertAll操作:

const initialState = {};
export const someSlice = createSlice({
  name: 'something',
  initialState,
  extraReducers: (builder) => builder.addCase(revertAll, () => initialState),
  reducers: {}
});

可以像往常一样创建商店:

export const store = configureStore({
  reducer: {
    someReducer: someSlice.reducer,
  }
})

在你的React代码中,你可以使用useDispatch钩子调用revertAll操作:

export function SomeComponent() {
  const dispatch = useDispatch();

  return <span onClick={() => dispatch(revertAll())}>Reset</span>
}

2
哇!这就是我一直在寻找的! - evisotskiy
1
这段代码虽然可用,但我们需要在所有的reducer中添加重复的代码。希望有一种更优雅的方法来实现避免代码重复。 - Dattatreya Kugve
这是2023年唯一有效的方法。谢谢。 - Ujith Nimantha
谢谢@Blee。请问我需要关于如何进行调度的澄清。由于我们在所有片上都有反向全部,那么在调度之前如何将它们合并? - SwiftDev
这就是extraReducers的作用:它们允许所有切片对同一操作作出响应。dispatch的工作方式与其他dispatch相同,但现在它会触发多个reducers - Blee
显示剩余2条评论

18

这对我很有用(2020年中后期)。以您的代码上下文作为示例进行了格式化。

const initialState = {
  returned: [],
};

const showOnReviewSlice = createSlice({
  name: 'showOnReview',
  initialState,
  reducers: {
    reset: () => initialState,
  },
});


1
这些都对我没用 :( 它只是说 initialState 未定义。我的错忘记定义初始状态。 - Rakesh Kumar
这是更好的样式化答案。 - Ansjovis86

13

在我身上(2020年中期)直接用initialState替换state并没有起作用,我最终解决的方法是使用Object.assign()复制每个属性。这样可以解决问题:

const showOnReviewSlice = createSlice({
    name: 'showOnReview',
    initialState: {
        returned: []
    },
    reducers: {
        reset(state) {
            Object.assign(state, initialState)
        }
    }
});

1
你能否回答我的问题:https://dev59.com/fFIG5IYBdhLWcg3wliQ1 - DevLoverUmar
非常感谢!其他方法都没用! - nmu

8
我们这样做,伙计们。
假设您想在注销时清除所有数据。
在store.tsx文件中:
import { AnyAction, combineReducers, configureStore } from '@reduxjs/toolkit';
import authReducer from './slices/authSlice'
import messageReducer from './slices/messageSlice'



const appReducer = combineReducers({
  auth: authReducer,
  message: messageReducer,
});

const reducerProxy = (state: any, action: AnyAction) => {
  if(action.type === 'logout/LOGOUT') {
    return appReducer(undefined, action);
  }
  return appReducer(state, action);
}

export const store = configureStore({
  reducer: reducerProxy,
});

然后你可以创建一个这样的thunk:

export const logout = createAsyncThunk(
    "auth/logout",
    async function (_payload, thunkAPI) {
        thunkAPI.dispatch({ type: 'logout/LOGOUT' });
        console.log('logged out')
    }
);

在您分派了注销操作后,您还可以刷新浏览器,这样它就会自动将用户重定向到登录页面。

function MyReactComponent() {
   const dispatch = useDispatch()

   function myLogoutOnClickHandler() {
      dispatch(logout())
      window.location = window.location;
   }
   ...

}

6
与先前的答案一样,在我这种情况下,即使您使用工具包适配器,仅仅设置初始状态也无法正常工作。
reducers: {
        // Other reducers
         state = tasksAdapter.getInitialState({
                status: 'idle',
                error: null,
                current: null
            })
        }
    },


相反,你应该使用 Object.assign(),猜测它与内部的immer库行为有关


1
你是对的。在v1.5.0中,你必须使用Object.assign(state, initialState)来完成它。 - Leonardo Viada

3

试试这个。在我的情况下,当某个动作被调度时,我想返回所有切片到初始状态

  • 首先,让我们创建动作:
import { createAction } from '@reduxjs/toolkit';

export const resetPanelsAction = createAction('resetPanelsData');
  • 创建我们的商店时,我们在中间件中保存initialState的副本:
import { Middleware } from '@reduxjs/toolkit';

export const resetDataMiddleware: Middleware =
    ({ getState }) =>
    (next) => {
        // "Caching" our initial app state
        const initialAppState = getState();

        return (action) => {
            // Let's add the condition that if the action is of 
            // type resetData, then add our cached state to its payload
            if (action.type === 'resetData') {
                const actionWithInitialAppState = {
                    ...action,
                    payload: initialAppState,
                };

                return next(actionWithInitialAppState);
            }

            return next(action);
        };
    };
  • 差不多完成了!现在让我们稍微修改一下我们的根reducer,添加一个包装器来检查操作类型,如果等于resetData,则返回combinedReducers和我们的initialState(在payload中),以使内容更加通俗易懂。
import { AnyAction } from 'redux';
import { combineReducers } from '@reduxjs/toolkit';

export const combinedReducers = combineReducers({
    /** Your reducers */
});

export const rootReducer = (
    state: ReturnType<typeof combinedReducers> | undefined,
    action: AnyAction,
) => {
    if (action.type === 'resetPanelsData') {
        return combinedReducers(action.payload, action);
    }

    return combinedReducers(state, action);
};

0
您可以使用扩展运算符来设置initialState
const initialState: {
  returned: unknown[] //set your type here
} = {
  returned: []
}

const showOnReviewSlice = createSlice({
  name: 'showOnReview',
  initialState,
  reducers: {
    reset() {
      return {
        ...initialState
      }
    }
  }
});

0
您还可以通过以下方式重置和更改一些初始参数:
const intialState = {
  name: "",
  surname: "",
}

const showOnReviewSlice = createSlice({
    name: 'showOnReview',
    initialState,
    reducers: {
        reset: () => initialState, ...initialState.name = "Example"
    }
});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接