简体   繁体   中英

unable to update the state through custom react hook

I am trying to create a custom hook which returns a custom drawer and a button(to toggle the state of drawer). I am managing the state in custom hook itself.

This is my custom hook for returning the drawer and a button

import React from "react";
import clsx from "clsx";
import { makeStyles } from "@material-ui/core/styles";
import Drawer from "@material-ui/core/Drawer";
import List from "@material-ui/core/List";
import Divider from "@material-ui/core/Divider";
import ListItem from "@material-ui/core/ListItem";
import ListItemIcon from "@material-ui/core/ListItemIcon";
import ListItemText from "@material-ui/core/ListItemText";
import InboxIcon from "@material-ui/icons/MoveToInbox";
import MailIcon from "@material-ui/icons/Mail";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faBars } from "@fortawesome/free-solid-svg-icons";
import { Button } from "@material-ui/core";

const useStyles = makeStyles({
  list: {
    width: 250
  },
  fullList: {
    width: "auto"
  }
});

export default function useTemporaryDrawer(toggle) {
  const classes = useStyles();

  const [state, setState] = React.useState({
    right: false
  });

  const toggleDrawer = (anchor, open) => (event) => {
    if (
      event.type === "keydown" &&
      (event.key === "Tab" || event.key === "Shift")
    ) {
      return;
    }
    alert("setting");
    setState({ ...state, [anchor]: open });
  };

  const onButtonClick = (e) => {
    toggleDrawer("right", true)(e);
  };

  const Toggler = (
    <Button
      style={{
        marginTop: "10px"
      }}
      onClick={onButtonClick}
      startIcon={<FontAwesomeIcon icon={faBars} style={{ color: "#fff" }} />}
    ></Button>
  );

  const list = (anchor) => (
    <div
      className={clsx(classes.list, {
        [classes.fullList]: anchor === "top" || anchor === "bottom"
      })}
      role="presentation"
      onClick={toggleDrawer(anchor, false)}
      onKeyDown={toggleDrawer(anchor, false)}
    >
      <List>
        {["Inbox", "Starred", "Send email", "Drafts"].map((text, index) => (
          <ListItem button key={text}>
            <ListItemIcon>
              {index % 2 === 0 ? <InboxIcon /> : <MailIcon />}
            </ListItemIcon>
            <ListItemText primary={text} />
          </ListItem>
        ))}
      </List>
      <Divider />
      <List>
        {["All mail", "Trash", "Spam"].map((text, index) => (
          <ListItem button key={text}>
            <ListItemIcon>
              {index % 2 === 0 ? <InboxIcon /> : <MailIcon />}
            </ListItemIcon>
            <ListItemText primary={text} />
          </ListItem>
        ))}
      </List>
    </div>
  );

  const CustomDrawer = (
    <Drawer
      anchor={"right"}
      open={state["right"]}
      onClose={toggleDrawer("right", false)}
    >
      {list("right")}
    </Drawer>
  );

  return {
    CustomDrawer,
    setState,
    state,
    Toggler
  };
}

Then, I am trying to update the state through Toggle button which I am using in Header. This is my header

import React from "react";
import styles from "./Header.module.css";
import useTemporaryDrawer from "../Drawer/useTemporaryDrawer";

const Header = (props) => {
  const { Toggler } = useTemporaryDrawer();

  return <div className={styles.headerForApp}>{Toggler}</div>;
};

export default Header;

When I press the toggle button, it does update the state but it does not update the open property of drawer. In short I am not able to open the drawer through toggle button. Please help.

Here is the sandbox https://codesandbox.io/s/customhooksnotupdatingstate-d7mfz?file=/src/components/Drawer/useTemporaryDrawer.js

If I have 2 components: A and B, and each of them have setState hook to update variable state , you won't expect setState('a') inside A to make any difference to state in B, will you? But then you create 2 components, each of them with their independent state and expect those states to be shared somehow. Toggle in Header changes state of Header, and Drawer in Dashboard had no visibility of these changes. As an option you can pass Toggler to the Header as a prop

<Header Toggler={Toggler} />
const Header = (props) => {
return <div className={styles.headerForApp}>{props.Toggler}</div>;
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM