how to make snackbar a global component withContext

Viewed 4257

I'm trying to use a snackbar component that takes an open and message prop and that I can display (set open to true) from any page of the app.

From what I understand I should use Context. But I'm not too sure where to start.

This is what I have so far

I'd like to have the snackbar at the highest parent component

import { createContext } from 'react';

export const SnackbarContext = createContext({});
 const [snack, setSnack] = useState({
    message: '',
    color: '',
    open: false,
  });
<SnackbarContext.Provider value={{ snack, setSnack }}>
  <Snackbar open={snack.open}>
    <Alert>
      {snack.message}
    </Alert>
  </Snackbar>
  <ViewContainer>
    <Switch>{switchRoutes}</Switch>
  </ViewContainer>
</SnackbarContext.Provider>

and be able to call it from any child component

import { SnackbarContext } from 'SnackbarContext';

const { snack, setSnack } = useContext(SnackbarContext);

and then change the props to snackbar like that

setSnack({ message: 'hello', open: true})
2 Answers

This solution actually works, I just made a typo

Here is a similar solution in Typescript

class Snack {
  message?: string;
  color?: AlertColor;
  autoHideDuration?: number;
  open: boolean;

  constructor(data: Snack) {
    this.message = data.message || '';
    this.color = data.color || 'info';
    this.autoHideDuration = data.autoHideDuration || 3000;
    this.open = data.open;
  }
}

export {Snack};

type SnackDefaultValue = {
  snack: Snack,
  setSnack: React.Dispatch<React.SetStateAction<Snack>>
};

export const SnackbarContext = createContext<SnackDefaultValue>({snack: new Snack({open: false}), setSnack: () => {}});

const SomeComponent: React.FC = (props) => {
  const [snack, setSnack] = useState(new Snack({open: false}));

  const handleClose = (event?: React.SyntheticEvent | Event, reason?: string) => {
    if (reason === 'clickaway') {
      return;
    }

    setSnack(new Snack({color: snack.color, open:false}));
  };

  return (
    <SnackbarContext.Provider value={{snack, setSnack}}>
      {/*Other components*/}
      <Snackbar open={snack.open} autoHideDuration={snack.autoHideDuration} onClose={handleClose}>
        <Alert severity={snack.color}>
          {snack.message || ''}
        </Alert>
      </Snackbar>
    </SnackbarContext.Provider>
  );
}

function someChildComponent() {
  const {snack, setSnack} = useContext(SnackbarContext);

  // Some event
  setSnack(new Snack({message: 'Some message', color:'success', autoHideDuration:1500, open: true}))
}
  
Related