Search code examples
reactjsaction

Need to call an alert message component from action in react


I've created a common component and exported it, i need to call that component in action based on the result from API. If the api success that alert message component will call with a message as "updated successfully". error then show with an error message.

calling service method in action. is there any way we can do like this? is it possible to call a component in action


Solution

  • You have many options.

    1. Redux

    If you are a fan of Redux, or your project already use Redux, you might want to do it like this.

    First declare the slice, provider and hook

    const CommonAlertSlice = createSlice({
        name: 'CommonAlert',
        initialState : {
            error: undefined
        },
        reducers: {
            setError(state, action: PayloadAction<string>) {
                state.error = action.payload;
            },
            clearError(state) {
                state.error = undefined;
            },
        }
    });
    
    export const CommonAlertProvider: React.FC = ({children}) => {
        const error = useSelector(state => state['CommonAlert'].error);
        const dispatch = useDispatch();
        return <>
            <MyAlert 
                visible={error !== undefined} 
                body={error} onDismiss={() => 
                dispatch(CommonAlertSlice.actions.clearError())} />
            {children}
        </>
    }
    
    export const useCommonAlert = () => {
        const dispatch = useDispatch();
        return {
            setError: (error: string) => dispatch(CommonAlertSlice.actions.setError(error)),
        }
    }
    
    

    And then use it like this.

    const App: React.FC = () => {
        return <CommonAlertProvider>
            <YourComponent />
        </CommonAlertProvider>
    }
    
    const YourComponent: React.FC = () => {
        const { setError } = useCommonAlert();
        useEffect(() => {
            callYourApi()
                .then(...)
                .catch(err => {
                    setError(err.message);
                });
        });
    
        return <> ... </>
    }
    
    

    2. React Context

    If you like the built-in React Context, you can make it more simpler like this.

    const CommonAlertContext = createContext({
        setError: (error: string) => {}
    });
    
    export const CommonAlertProvider: React.FC = ({children}) => {
        const [error, setError] = useState<string>();
        return <CommonAlertContext.Provider value={{
                   setError
               }}>
            <MyAlert 
                visible={error !== undefined} 
                body={error} onDismiss={() => setError(undefined)} />
            {children}
        </CommonAlertContext.Provider>
    }
    
    export const useCommonAlert = () => useContext(CommonAlertContext);
    

    And then use it the exact same way as in the Redux example.

    3. A Hook Providing a Render Method

    This option is the simplest.

    export const useAlert = () => {
        const [error, setError] = useState<string>();
        return {
            setError,
            renderAlert: () => {
                return <MyAlert 
                          visible={error !== undefined} 
                          body={error} onDismiss={() => setError(undefined)} />
            }
        }
    }
    

    Use it.

    const YourComponent: React.FC = () => {
        const { setError, renderAlert } = useAlert();
    
        useEffect(() => {
            callYourApi()
                .then(...)
                .catch(err => {
                    setError(err.message);
                });
        });
    
        return <> 
                {renderAlert()} 
                ... 
        </>
    }