Berry React
v4.1.0
v4.1.0
  • Introduction
  • Package
  • Getting Started
    • Pre-requisites
    • Quick Start
    • Mock backend
    • Deployment
    • Licensing
  • Setup
    • Seed
    • To Existing Project
  • Folder Structure
  • State Management
  • Multi Language
  • Authentication
    • Firebase
    • Auth0
    • AWS Cognito
    • Supabase
  • API Calls
  • Routing
    • New Menu
    • Login as First Page
    • Skip Login
    • Render Menu from the backend
    • Remove menu render via backend
  • Theme
    • Configuration
    • Presets
    • Style
      • Color
      • Typography
      • Overrides
      • Shadows
    • Layouts
    • Logo
  • How to
    • Remove eslint
    • Remove prettier
  • Components
    • Avatar
    • AnimateButton
    • Accordion
    • Breadcrumbs
    • Chip
    • ImageList
    • MainCard
    • Transitions
    • SubCard
  • Dependencies
  • Support
    • Roadmap
    • Changelog
    • FAQ
  • Berry Eco System
Powered by GitBook
On this page
  • Context API
  • State
  • Designing Actions
  • Writing Reducers

Was this helpful?

State Management

Managing context, state and hooks

Context API

We are using context for login methods - Auth0, JWT, Firebase.

src/contexts/configContext.jsx
....
// project import
import defaultConfig from 'config';
import useLocalStorage from 'hooks/useLocalStorage';
....

// ==============================|| CONFIG CONTEXT & PROVIDER ||============================== //

const ConfigContext = createContext(initialState);

function ConfigProvider({ children }) {

....
    const onChangeMenuOrientation = (menuOrientation) => {
        setConfig({
            ...config,
            menuOrientation
        });
    };

    const onChangeMiniDrawer = (miniDrawer) => {
        setConfig({
            ...config,
            miniDrawer
        });
    };

    const onChangeMode = (mode) => {
        setConfig({
            ...config,
            mode
        });
    };
....

 return (
        <ConfigContext
            value={{
                ...config,
                onChangeMenuOrientation,
                onChangeMiniDrawer,
                onChangeMode,
                onChangePresetColor,
                onChangeLocale,
                onChangeDirection,
                onChangeContainer,
                onChangeFontFamily,
                onChangeBorderRadius,
                onChangeOutlinedField,
                onReset
            }}
        >
            {children}
        </ConfigContext>
    );
}

ConfigProvider.propTypes = {
    children: PropTypes.node
};

export { ConfigProvider, ConfigContext };
src/contexts/configContext.tsx
....

// project import
import defaultConfig, { MenuOrientation, ThemeMode, ThemeDirection } from 'config';
import useLocalStorage from 'hooks/useLocalStorage';

...

// ==============================|| CONFIG CONTEXT & PROVIDER ||============================== //

const ConfigContext = createContext(initialState);

type ConfigProviderProps = {
    children: ReactNode;
};

function ConfigProvider({ children }: ConfigProviderProps) {
const [config, setConfig] = useLocalStorage('berry-config-vite-ts', {
        menuOrientation: initialState.menuOrientation,
        miniDrawer: initialState.miniDrawer,
        fontFamily: initialState.fontFamily,
        borderRadius: initialState.borderRadius,
        outlinedFilled: initialState.outlinedFilled,
        mode: initialState.mode,
        presetColor: initialState.presetColor,
        i18n: initialState.i18n,
        themeDirection: initialState.themeDirection,
        container: initialState.container
    });

    const onChangeMenuOrientation = (menuOrientation: MenuOrientation) => {
        setConfig({
            ...config,
            menuOrientation
        });
    };
    
    ....

    return (
            <ConfigContext
                value={{
                    ...config,
                    onChangeMenuOrientation,
                    onChangeMiniDrawer,
                    onChangeMode,
                    onChangePresetColor,
                    onChangeLocale,
                    onChangeDirection,
                    onChangeContainer,
                    onChangeFontFamily,
                    onChangeBorderRadius,
                    onChangeOutlinedField,
                    onReset
                }}
            >
                {children}
            </ConfigContext>
        );
    }

export { ConfigProvider, ConfigContext };

State

export const initialState = {
    isOpen: 'dashboard', //for active default menu
    navType: config.theme,
    locale: config.i18n,
    rtlLayout: false, // rtlLayout: config.rtlLayout,
    opened: true
};

Designing Actions

We designed the state structure based on the app's requirements.

Based on that list of things that can happen, we created list of actions that our application will use:

export const LOGIN = 'LOGIN';
export const LOGOUT = 'LOGOUT';
export const REGISTER = 'REGISTER';
export const FIREBASE_STATE_CHANGED = 'FIREBASE_STATE_CHANGED';

Writing Reducers

Creating the Root Reducer - A Redux app really only has one reducer function: the "root reducer" function

src/store/slice/contact.js
...
// project imports
import axios from 'utils/axios';
import { dispatch } from '../index';
...

...
const slice = createSlice({
    name: 'contact',
    initialState,
    reducers: {
        // HAS ERROR
        hasError(state, action) {
            state.error = action.payload;
        },

        // GET CONTACTS
        getContactsSuccess(state, action) {
            state.contacts = action.payload;
        },

        // MODIFY CONTACT
        modifyContactSuccess(state, action) {
            state.contacts = action.payload;
        }
    }
});
...

export function getContacts() {
    return async () => {
        try {
            const response = await axios.get('/api/contact/list');
            dispatch(slice.actions.getContactsSuccess(response.data.contacts));
        } catch (error) {
            dispatch(slice.actions.hasError(error));
        }
    };
}

export function modifyContact(contact) {
    return async () => {
        try {
            const response = await axios.post('/api/contact/modify', contact);
            dispatch(slice.actions.modifyContactSuccess(response.data));
        } catch (error) {
            dispatch(slice.actions.hasError(error));
        }
    };
}
src/store/slice/contact.ts
...
// project imports
import axios from 'utils/axios';
import { dispatch } from '../index';
...

...
// Reducer
export default slice.reducer;
...

export function getContacts() {
    return async () => {
        try {
            const response = await axios.get('/api/contact/list');
            dispatch(slice.actions.getContactsSuccess(response.data.contacts));
        } catch (error) {
            dispatch(slice.actions.hasError(error));
        }
    };
}

export function modifyContact(contact: UserProfile) {
    return async () => {
        try {
            const response = await axios.post('/api/contact/modify', contact);
            dispatch(slice.actions.modifyContactSuccess(response.data));
        } catch (error) {
            dispatch(slice.actions.hasError(error));
        }
    };
}

Last updated 21 days ago

Was this helpful?