mirror of
https://github.com/strapi/strapi.git
synced 2025-11-10 07:10:11 +00:00
feat(admin): implement redux-toolkit
This commit is contained in:
parent
4fcaf0f227
commit
57aef2ac2b
@ -11,8 +11,8 @@ import { BrowserRouter } from 'react-router-dom';
|
|||||||
import Logo from './assets/images/logo-strapi-2022.svg';
|
import Logo from './assets/images/logo-strapi-2022.svg';
|
||||||
import { LANGUAGE_LOCAL_STORAGE_KEY } from './components/LanguageProvider';
|
import { LANGUAGE_LOCAL_STORAGE_KEY } from './components/LanguageProvider';
|
||||||
import Providers from './components/Providers';
|
import Providers from './components/Providers';
|
||||||
import { customFields, Plugin } from './core/apis';
|
import { customFields, Plugin, Reducers } from './core/apis';
|
||||||
import configureStore from './core/store/configureStore';
|
import { configureStore } from './core/store/configureStore';
|
||||||
import { basename, createHook } from './core/utils';
|
import { basename, createHook } from './core/utils';
|
||||||
import {
|
import {
|
||||||
INJECT_COLUMN_IN_TABLE,
|
INJECT_COLUMN_IN_TABLE,
|
||||||
@ -26,7 +26,7 @@ import App from './pages/App';
|
|||||||
import languageNativeNames from './translations/languageNativeNames';
|
import languageNativeNames from './translations/languageNativeNames';
|
||||||
|
|
||||||
class StrapiApp {
|
class StrapiApp {
|
||||||
constructor({ adminConfig, appPlugins, library, middlewares, reducers }) {
|
constructor({ adminConfig, appPlugins, library, middlewares }) {
|
||||||
this.customConfigurations = adminConfig.config;
|
this.customConfigurations = adminConfig.config;
|
||||||
this.customBootstrapConfiguration = adminConfig.bootstrap;
|
this.customBootstrapConfiguration = adminConfig.bootstrap;
|
||||||
this.configurations = {
|
this.configurations = {
|
||||||
@ -43,7 +43,7 @@ class StrapiApp {
|
|||||||
this.library = library;
|
this.library = library;
|
||||||
this.middlewares = middlewares;
|
this.middlewares = middlewares;
|
||||||
this.plugins = {};
|
this.plugins = {};
|
||||||
this.reducers = reducers;
|
this.reducers = Reducers({});
|
||||||
this.translations = {};
|
this.translations = {};
|
||||||
this.hooksDict = {};
|
this.hooksDict = {};
|
||||||
this.admin = {
|
this.admin = {
|
||||||
|
|||||||
@ -1,47 +0,0 @@
|
|||||||
import { applyMiddleware, combineReducers, compose, createStore } from 'redux';
|
|
||||||
|
|
||||||
const configureStore = (appMiddlewares, appReducers) => {
|
|
||||||
let composeEnhancers = compose;
|
|
||||||
|
|
||||||
const middlewares = [];
|
|
||||||
|
|
||||||
appMiddlewares.forEach((middleware) => {
|
|
||||||
middlewares.push(middleware());
|
|
||||||
});
|
|
||||||
|
|
||||||
// If Redux Dev Tools are installed, enable them
|
|
||||||
if (
|
|
||||||
process.env.NODE_ENV !== 'production' &&
|
|
||||||
typeof window === 'object' &&
|
|
||||||
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
|
|
||||||
) {
|
|
||||||
composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({});
|
|
||||||
}
|
|
||||||
|
|
||||||
const store = createStore(
|
|
||||||
createReducer(appReducers, {}),
|
|
||||||
{},
|
|
||||||
composeEnhancers(applyMiddleware(...middlewares))
|
|
||||||
);
|
|
||||||
|
|
||||||
// Add a dictionary to keep track of the registered async reducers
|
|
||||||
store.asyncReducers = {};
|
|
||||||
|
|
||||||
// Create an inject reducer function
|
|
||||||
// This function adds the async reducer, and creates a new combined reducer
|
|
||||||
store.injectReducer = (key, asyncReducer) => {
|
|
||||||
store.asyncReducers[key] = asyncReducer;
|
|
||||||
store.replaceReducer(createReducer(appReducers, store.asyncReducers));
|
|
||||||
};
|
|
||||||
|
|
||||||
return store;
|
|
||||||
};
|
|
||||||
|
|
||||||
const createReducer = (appReducers, asyncReducers) => {
|
|
||||||
return combineReducers({
|
|
||||||
...appReducers,
|
|
||||||
...asyncReducers,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export default configureStore;
|
|
||||||
114
packages/core/admin/admin/src/core/store/configureStore.ts
Normal file
114
packages/core/admin/admin/src/core/store/configureStore.ts
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
import {
|
||||||
|
configureStore,
|
||||||
|
StoreEnhancer,
|
||||||
|
Middleware,
|
||||||
|
Reducer,
|
||||||
|
combineReducers,
|
||||||
|
createSelector,
|
||||||
|
Selector,
|
||||||
|
} from '@reduxjs/toolkit';
|
||||||
|
import { useDispatch, useStore, TypedUseSelectorHook, useSelector } from 'react-redux';
|
||||||
|
|
||||||
|
// @ts-expect-error no types, yet.
|
||||||
|
import rbacProviderReducer from '../../components/RBACProvider/reducer';
|
||||||
|
// @ts-expect-error no types, yet.
|
||||||
|
import rbacManagerReducer from '../../content-manager/hooks/useSyncRbac/reducer';
|
||||||
|
// @ts-expect-error no types, yet.
|
||||||
|
import cmAppReducer from '../../content-manager/pages/App/reducer';
|
||||||
|
// @ts-expect-error no types, yet.
|
||||||
|
import editViewLayoutManagerReducer from '../../content-manager/pages/EditViewLayoutManager/reducer';
|
||||||
|
// @ts-expect-error no types, yet.
|
||||||
|
import listViewReducer from '../../content-manager/pages/ListView/reducer';
|
||||||
|
// @ts-expect-error no types, yet.
|
||||||
|
import editViewCrudReducer from '../../content-manager/sharedReducers/crudReducer/reducer';
|
||||||
|
// @ts-expect-error no types, yet.
|
||||||
|
import appReducer from '../../pages/App/reducer';
|
||||||
|
|
||||||
|
const createReducer = (
|
||||||
|
appReducers: Record<string, Reducer>,
|
||||||
|
asyncReducers: Record<string, Reducer>
|
||||||
|
) => {
|
||||||
|
return combineReducers({
|
||||||
|
...appReducers,
|
||||||
|
...asyncReducers,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Static reducers are ones we know, they live in the admin package.
|
||||||
|
*/
|
||||||
|
const staticReducers: Record<string, Reducer> = {
|
||||||
|
admin_app: appReducer,
|
||||||
|
rbacProvider: rbacProviderReducer,
|
||||||
|
'content-manager_app': cmAppReducer,
|
||||||
|
'content-manager_listView': listViewReducer,
|
||||||
|
'content-manager_rbacManager': rbacManagerReducer,
|
||||||
|
'content-manager_editViewLayoutManager': editViewLayoutManagerReducer,
|
||||||
|
'content-manager_editViewCrudReducer': editViewCrudReducer,
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
const injectReducerStoreEnhancer: (appReducers: Record<string, Reducer>) => StoreEnhancer =
|
||||||
|
(appReducers) =>
|
||||||
|
(next) =>
|
||||||
|
(...args) => {
|
||||||
|
const store = next(...args);
|
||||||
|
|
||||||
|
const asyncReducers: Record<string, Reducer> = {};
|
||||||
|
|
||||||
|
return {
|
||||||
|
...store,
|
||||||
|
asyncReducers,
|
||||||
|
injectReducer: (key: string, asyncReducer: Reducer) => {
|
||||||
|
asyncReducers[key] = asyncReducer;
|
||||||
|
// @ts-expect-error we dynamically add reducers which makes the types uncomfortable.
|
||||||
|
store.replaceReducer(createReducer(appReducers, asyncReducers));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description This is the main store configuration function, injected Reducers use our legacy app.addReducer API,
|
||||||
|
* which we're trying to phase out. App Middlewares could potentially be improved...?
|
||||||
|
*/
|
||||||
|
const configureStoreImpl = (
|
||||||
|
appMiddlewares: Array<() => Middleware>,
|
||||||
|
injectedReducers: Record<string, Reducer>
|
||||||
|
) => {
|
||||||
|
const coreReducers = { ...staticReducers, ...injectedReducers };
|
||||||
|
|
||||||
|
const store = configureStore({
|
||||||
|
reducer: createReducer(coreReducers, {}),
|
||||||
|
devTools: process.env.NODE_ENV !== 'production',
|
||||||
|
middleware: (getDefaultMiddleware) => [
|
||||||
|
...getDefaultMiddleware(),
|
||||||
|
...appMiddlewares.map((m) => m()),
|
||||||
|
],
|
||||||
|
enhancers: [injectReducerStoreEnhancer(coreReducers)],
|
||||||
|
});
|
||||||
|
|
||||||
|
return store;
|
||||||
|
};
|
||||||
|
|
||||||
|
type Store = ReturnType<typeof configureStoreImpl> & {
|
||||||
|
asyncReducers: Record<string, Reducer>;
|
||||||
|
injectReducer: (key: string, asyncReducer: Reducer) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
type RootState = ReturnType<Store['getState']>;
|
||||||
|
type AppDispatch = Store['dispatch'];
|
||||||
|
|
||||||
|
const useTypedDispatch: () => AppDispatch = useDispatch;
|
||||||
|
const useTypedStore = useStore as () => Store;
|
||||||
|
const useTypedSelector: TypedUseSelectorHook<RootState> = useSelector;
|
||||||
|
|
||||||
|
const createTypedSelector = <TResult>(selector: Selector<RootState, TResult>) =>
|
||||||
|
createSelector((state: RootState) => state, selector);
|
||||||
|
|
||||||
|
export {
|
||||||
|
useTypedDispatch,
|
||||||
|
useTypedStore,
|
||||||
|
useTypedSelector,
|
||||||
|
configureStoreImpl as configureStore,
|
||||||
|
createTypedSelector,
|
||||||
|
};
|
||||||
|
export type { RootState };
|
||||||
@ -2,10 +2,9 @@ import { getFetchClient } from '@strapi/helper-plugin';
|
|||||||
import { createRoot } from 'react-dom/client';
|
import { createRoot } from 'react-dom/client';
|
||||||
|
|
||||||
import appCustomisations from './app';
|
import appCustomisations from './app';
|
||||||
import { Components, Fields, Middlewares, Reducers } from './core/apis';
|
import { Components, Fields, Middlewares } from './core/apis';
|
||||||
// eslint-disable-next-line import/extensions
|
// eslint-disable-next-line import/extensions
|
||||||
import plugins from './plugins';
|
import plugins from './plugins';
|
||||||
import appReducers from './reducers';
|
|
||||||
|
|
||||||
window.strapi = {
|
window.strapi = {
|
||||||
/**
|
/**
|
||||||
@ -35,7 +34,6 @@ const library = {
|
|||||||
fields: Fields(),
|
fields: Fields(),
|
||||||
};
|
};
|
||||||
const middlewares = Middlewares();
|
const middlewares = Middlewares();
|
||||||
const reducers = Reducers({ appReducers });
|
|
||||||
|
|
||||||
const MOUNT_NODE = document.getElementById('app');
|
const MOUNT_NODE = document.getElementById('app');
|
||||||
|
|
||||||
@ -69,7 +67,6 @@ const run = async () => {
|
|||||||
adminConfig: customConfig,
|
adminConfig: customConfig,
|
||||||
bootstrap: customConfig,
|
bootstrap: customConfig,
|
||||||
middlewares,
|
middlewares,
|
||||||
reducers,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
await app.bootstrapAdmin();
|
await app.bootstrapAdmin();
|
||||||
|
|||||||
@ -1,23 +0,0 @@
|
|||||||
import rbacProviderReducer from './components/RBACProvider/reducer';
|
|
||||||
import rbacManagerReducer from './content-manager/hooks/useSyncRbac/reducer';
|
|
||||||
import cmAppReducer from './content-manager/pages/App/reducer';
|
|
||||||
import editViewLayoutManagerReducer from './content-manager/pages/EditViewLayoutManager/reducer';
|
|
||||||
import listViewReducer from './content-manager/pages/ListView/reducer';
|
|
||||||
import editViewCrudReducer from './content-manager/sharedReducers/crudReducer/reducer';
|
|
||||||
import appReducer from './pages/App/reducer';
|
|
||||||
|
|
||||||
const contentManagerReducers = {
|
|
||||||
'content-manager_app': cmAppReducer,
|
|
||||||
'content-manager_listView': listViewReducer,
|
|
||||||
'content-manager_rbacManager': rbacManagerReducer,
|
|
||||||
'content-manager_editViewLayoutManager': editViewLayoutManagerReducer,
|
|
||||||
'content-manager_editViewCrudReducer': editViewCrudReducer,
|
|
||||||
};
|
|
||||||
|
|
||||||
const reducers = {
|
|
||||||
admin_app: appReducer,
|
|
||||||
rbacProvider: rbacProviderReducer,
|
|
||||||
...contentManagerReducers,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default reducers;
|
|
||||||
@ -44,6 +44,7 @@
|
|||||||
"@casl/ability": "6.5.0",
|
"@casl/ability": "6.5.0",
|
||||||
"@pmmmwh/react-refresh-webpack-plugin": "0.5.10",
|
"@pmmmwh/react-refresh-webpack-plugin": "0.5.10",
|
||||||
"@radix-ui/react-toolbar": "1.0.4",
|
"@radix-ui/react-toolbar": "1.0.4",
|
||||||
|
"@reduxjs/toolkit": "1.9.7",
|
||||||
"@strapi/data-transfer": "4.14.4",
|
"@strapi/data-transfer": "4.14.4",
|
||||||
"@strapi/design-system": "1.12.2",
|
"@strapi/design-system": "1.12.2",
|
||||||
"@strapi/helper-plugin": "4.14.4",
|
"@strapi/helper-plugin": "4.14.4",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user