I made a custom Snackbar component in React using Material-ui (and Typescript). I have trouble understanding how the spread operator and await work. (Example here: https://codesandbox.io/s/gifted-hopper-tkkpi?file=/src/App.tsx:1311-1380)
Full code:
import React, { FunctionComponent, useEffect } from "react";
import Button from "@material-ui/core/Button";
import Snackbar from "@material-ui/core/Snackbar";
import { Color } from "@material-ui/lab";
import { Alert } from "@material-ui/lab";
interface SnackbarModel {
open: boolean;
severity?: Color;
message: string;
}
const CustomSnackbar: FunctionComponent<SnackbarModel> = (props) => {
const [opened, setOpened] = React.useState(false);
useEffect(() => {
if (props.open) {
setOpened(true);
}
}, [props.open]);
const handleClose = (event: React.ChangeEvent<object>, reason: string) => {
if (reason === "clickaway") {
return;
}
setOpened(false);
};
return (
<div>
<Snackbar
open={opened}
autoHideDuration={2000}
onClose={handleClose}
anchorOrigin={{ vertical: "top", horizontal: "center" }}
>
<Alert severity={props.severity}>{props.message}</Alert>
</Snackbar>
</div>
);
};
export default function App() {
const [snackbar, setSnackbar] = React.useState<SnackbarModel>({
open: false,
message: ""
});
async function handleClick() {
await fetch(Stuff...)
// Working as desired
//setSnackbar({open: true, severity: "success", message: "Snackbar"});
//setSnackbar({open: false, severity: "success", message: "Snackbar"});
// Somehow not working
setSnackbar({ open: true, severity: "success", message: "Snackbar" });
setSnackbar({ ...snackbar, open: false });
}
return (
<div>
<CustomSnackbar
open={snackbar.open}
message={snackbar.message}
severity={snackbar.severity}
/>
<Button variant="contained" onClick={handleClick}>
Snackbar
</Button>
</div>
);
}
I trigger the Snackbar to open with
const [snackbar, setSnackbar] = React.useState<SnackbarModel>({
open: false,
message: ""
});
async function handleClick() {
await fetch(Stuff)
setSnackbar({open: true, severity: "success", message: "Snackbar"})
setSnackbar({open: false, severity: "success", message: "Snackbar"});
}
The Snackbar automatically closes after a set amount of Time. "open" only triggers the Snackbar and doesn't control the setOpen-state of the Snackbar.
Now I tried:
setSnackbar({ open: true, severity: "success", message: "Snackbar" });
console.log(snackbar); //gives you: Object {open: false, message: ""}
setSnackbar({ ...snackbar, open: false });
This successfully triggers the Snackbar but the message/text is lost.
Question 1: Shouldn't "...snackbar" still have "message: 'Snackbar' " saved?
For some reason i also have to make the function async and await the first "setSnackbar" if I don't use "await fetch(Stuff...):
async function handleClick() {
//working as desired
await setSnackbar({open: true, severity: "success", message: "Snackbar"});
setSnackbar({open: false, severity: "success", message: "Snackbar"});
// OR
//not working as desired
await setSnackbar({ open: true, severity: "success", message: "Snackbar" });
setSnackbar({ ...snackbar, open: false });
}
Altough the await on "setSnackbar" is apparently not needed if you first have another line of code you await. In my use case this works:
async function handleClick() {
await fetch(Stuff...)
setSnackbar({open: true, severity: "success", message: "Snackbar"});
setSnackbar({open: false, severity: "success", message: "Snackbar"});
}
Question 2: Can someone explain why the await is required/not required?