dmikester1
dmikester1

Reputation: 1362

State variable not changing from context

I must be setting up my context or state wrong. But for some reason I cannot change my showDetails state. It is supposed to show a hidden column when that changes to true conditionally adding the bootstrap class d-none. I have a click event on my Order component that runs setShowDetails(true) and it's not working. The other stuff in that function do run.

Relevant code from my Order component:

const Order = props => {
  const { orderID } = props;
  const { setShowDetails } = useScheduleActionsContext();

  // show the details section when user clicks an order
  const showDetails = orderID => {
    console.log("showDetails function!");
    // needed to fix an issue with doubled borders between the columns
    document.querySelector(".lines .col.last").style.borderRightWidth = "0px";
    setShowDetails(true);
  };

  return (
    <MyOrder className={"order"} onClick={e => showDetails(orderID, e)}>
      <div className={"orderID"}>{orderID}</div>
      <h3>Order</h3>
    </MyOrder>
  );
};

Then my DetailsColumn component has this in it:

const { showDetails } = useScheduleContext();
  const { setShowDetails } = useScheduleActionsContext();

  // determine whether to show the details section based on the passed
  // in prop showDetails
  const className =
    "col details-column text-center" + (showDetails ? "" : " d-none");

Here is my entire context file:

import React, {
  createContext,
  useContext,
  useEffect,
  useState,
  useMemo
} from "react";
import { useGlobalSpinnerActionsContext } from "./GlobalSpinnerContext";
import PropTypes from "prop-types";

// export const ScheduleContext = createContext({
//   title: "My title"
// });

const pageTitle = "My Title";

const initialValues = {
  title: pageTitle,
  filteredOrders: [],
  columns: []
};

const ScheduleContext = createContext(initialValues);
const ScheduleActionsContext = createContext({});

export const useScheduleContext = () => useContext(ScheduleContext);
export const useScheduleActionsContext = () =>
  useContext(ScheduleActionsContext);

export const ScheduleProvider2 = props => {
  const setGlobalSpinner = useGlobalSpinnerActionsContext();
  setGlobalSpinner(true);
  console.log(setGlobalSpinner);

  const [context, setContext] = useState({});
  // eslint-disable-next-line no-unused-vars
  const [orders, setOrders] = useState([]);
  // eslint-disable-next-line no-unused-vars
  const [filteredOrders, setFilteredOrders] = useState([]);
  // eslint-disable-next-line no-unused-vars
  const [pendingOrderIDs, setPendingOrderIDs] = useState([]);
  const [lineType, setLineType] = useState(pageTitle);
  const [title, setTitle] = useState(pageTitle);
  const [columns, setColumns] = useState([]);
  const [showDetails, setShowDetails] = useState(false);

  useEffect(() => {
    setGlobalSpinner(true);
    console.log("we are running useEffect in context!!!");
    const fetchPendingOrders = async () => {
      const ordersURL = "https://randomuser.me/api";
      return await fetch(ordersURL, {
        cache: "no-cache", // *default, no-cache, reload, force-cache, only-if-cached
        headers: {
          "Content-Type": "application/json"
        },
        referrerPolicy: "no-referrer" // no-referrer, *client
      });
    };
    fetchPendingOrders()
      .then(result => {
        return result.json();
      })
      .then(data => {
        const tempOrders = data.results.map((el, index) => {
          return {
            id: index,
            gender: el.gender
          };
        });
        console.log("tempOrders: ", tempOrders);
        setOrders(tempOrders);
        setFilteredOrders(tempOrders);
        const pendingOrderIDVals = tempOrders.map(function(val) {
          return val.id;
        });
        setPendingOrderIDs(pendingOrderIDVals);

        const contextValue = {
          orders: tempOrders,
          setOrders,
          showDetails,
          title,
          columns
        };
        setContext(contextValue);
        setGlobalSpinner(false);
        console.log(contextValue);
      })
      .catch(e => {
        console.log(e);
      });
  }, [setGlobalSpinner]);

  const actionsValues = useMemo(() => {
    return {
      setLineType,
      setColumns,
      setTitle,
      setShowDetails,
      setFilteredOrders,
      setPendingOrderIDs
    };
  }, []);

  return (
    <ScheduleContext.Provider value={context}>
      <ScheduleActionsContext.Provider value={actionsValues}>
        {props.children}
      </ScheduleActionsContext.Provider>
    </ScheduleContext.Provider>
  );
};

ScheduleProvider2.propTypes = {
  children: PropTypes.oneOfType([
    PropTypes.arrayOf(PropTypes.node),
    PropTypes.node
  ]).isRequired
};

I've also created a code sandbox so that it can be tested and played with and the code can be tweaked. If you click on one of the blue Order boxes it is supposed to show the Order Details column. https://codesandbox.io/s/romantic-lamarr-lb11g

Upvotes: 0

Views: 243

Answers (1)

Maksym Bezruchko
Maksym Bezruchko

Reputation: 1258

Okay, I found out why it does not work.

  1. You must add showDetails: false to initialValues of the ScheduleContext component.
  2. You must add showDetails as a dependency to useEffect hook like:
useEffect(() => {
   ...
 }, [setGlobalSpinner, showDetails]);

Upvotes: 1

Related Questions