1

I'm trying to execute a function that executes other functions. The function itself executes but the functions inside of it do not. I thought I had a good grasp on React mechanics and it's lifecycle but I guess not. I do not understand why react is acting this way. Hoping for guidance/an explanation on the react component lifecycle and what about it that prevents this particular code from working.

getInfo.jsx

import { useState, useEffect } from "react";

export const useGetCompletionData = () => {
  const [sandIsActive, setSandActive] = useState(false);
  const [dragonIsActive, setDragonActive] = useState(false);
  const [splinterIsActive, setSplinterActive] = useState(false);
  const [tigerIsActive, setTigerActive] = useState(false);
  const [reptileIsActive, setReptileActive] = useState(false);
  const [jungleIsActive, setJungleActive] = useState(false);
  const [totalCamo, setTotalCamo] = useState(0);
  const [goldIsActive, setGoldActive] = useState(false);

  const handleSandClick = (event) => {
    // ️ toggle isActive state on click
    setSandActive((current) => !current);
    if (sandIsActive) {
      setTotalCamo((prev) => prev - 1);
    } else {
      setTotalCamo((prev) => prev + 1);
    }
  };

  const handleDragonClick = (event) => {
    // ️ toggle isActive state on click
    setDragonActive((current) => !current);
    if (dragonIsActive) {
      setTotalCamo((prev) => prev - 1);
    } else {
      setTotalCamo((prev) => prev + 1);
    }
  };

  const handleSplinterClick = (event) => {
    // ️ toggle isActive state on click
    setSplinterActive((current) => !current);
    if (splinterIsActive) {
      setTotalCamo((prev) => prev - 1);
    } else {
      setTotalCamo((prev) => prev + 1);
    }
  };

  const handleTigerClick = (event) => {
    // ️ toggle isActive state on click
    setTigerActive((current) => !current);
    if (tigerIsActive) {
      setTotalCamo((prev) => prev - 1);
    } else {
      setTotalCamo((prev) => prev + 1);
    }
  };

  const handleReptileClick = (event) => {
    // ️ toggle isActive state on click
    setReptileActive((current) => !current);
    if (reptileIsActive) {
      setTotalCamo((prev) => prev - 1);
    } else {
      setTotalCamo((prev) => prev + 1);
    }
  };

  const handleJungleClick = (event) => {
    // ️ toggle isActive state on click
    setJungleActive((current) => !current);
    if (jungleIsActive) {
      setTotalCamo((prev) => prev - 1);
    } else {
      setTotalCamo((prev) => prev + 1);
    }
  };

  const setAllCamos = (event) => {
    console.log("set all camos start");
    handleSandClick();
    handleDragonClick();
    handleSplinterClick();
    handleTigerClick();
    handleJungleClick();
    console.log("set all camos finished");
  };

  return {
    goldIsActive,
    setGoldActive,
    totalCamo,
    setTotalCamo,
    sandIsActive,
    handleSandClick,
    handleDragonClick,
    dragonIsActive,
    splinterIsActive,
    handleSplinterClick,
    tigerIsActive,
    handleTigerClick,
    handleReptileClick,
    reptileIsActive,
    jungleIsActive,
    handleJungleClick,
    setAllCamos,
  };
};

AR_list.jsx

import React from "react";
import CamoList from "../Completion/CamoList";
import { useState } from "react";
import { useGetCompletionData } from "../../hooks/getInfo";

export default function AR_LIST() {
  const [damascusPercent, setDamascusPercent] = useState(0);
  let { setAllCamos } = useGetCompletionData();
  return (
    <>
      <h1>Assault Rifle</h1>
      <div className="gun-grid">
        <div>
          <h1>ASM10</h1>
          <img
            src="https://i.imgur.com/4rk88oj.jpg"
            alt="ASM10"
            onDoubleClick={setAllCamos}
          />
          <CamoList
            damascusPercent={damascusPercent}
            setDamascusPercent={setDamascusPercent}
          />
        </div>

        <div>
          <h1>AK-47</h1>
          <img src="https://i.imgur.com/tiwEg6m.jpg" alt="AK47" />
          <CamoList
            damascusPercent={damascusPercent}
            setDamascusPercent={setDamascusPercent}
          />
        </div>

        <div>
          <h1>M16</h1>
          <img src="https://i.imgur.com/xGbpnJb.jpg" alt="M16" />
          <CamoList
            damascusPercent={damascusPercent}
            setDamascusPercent={setDamascusPercent}
          />
        </div>

        <div>
          <h1>M4</h1>
          <img src="https://i.imgur.com/LP0kr6K.jpg" alt="M4" />
          <CamoList
            damascusPercent={damascusPercent}
            setDamascusPercent={setDamascusPercent}
          />
        </div>

        <div>
          <h1>BK57</h1>
          <img src="https://i.imgur.com/mUp4KH7.jpg" alt="BK57" />
          <CamoList
            damascusPercent={damascusPercent}
            setDamascusPercent={setDamascusPercent}
          />
        </div>

        <div>
          <h1>LK24</h1>
          <img src="https://i.imgur.com/3iNpSfh.jpeg" alt="LK24" />
          <CamoList
            damascusPercent={damascusPercent}
            setDamascusPercent={setDamascusPercent}
          />
        </div>

        <div>
          <h1>AK117</h1>
          <img
            src="https://zilliongamer.com/uploads/codm/skins/assault/ak117/ak117-munitions-cod-mobile.jpg"
            alt="AK117"
          />
          <CamoList
            damascusPercent={damascusPercent}
            setDamascusPercent={setDamascusPercent}
          />
        </div>

        <div>
          <h1>M13</h1>
          <img
            src="https://zilliongamer.com/uploads/codm/weapons/ar/m13/m13-cod-mobile.jpg"
            alt="M13"
          />
          <CamoList
            damascusPercent={damascusPercent}
            setDamascusPercent={setDamascusPercent}
          />
        </div>

        <div>
          <h1>Kilo 141</h1>
          <img
            src="https://zilliongamer.com/uploads/codm/weapons/ar/kilo-141/kilo-141-call-of-duty-mobile.jpg"
            alt="Kilo 141"
          />
          <CamoList
            damascusPercent={damascusPercent}
            setDamascusPercent={setDamascusPercent}
          />
        </div>

        <div>
          <h1>KN-44</h1>
          <img src="https://i.imgur.com/OzlDWlk.jpg" alt="KN-44" />
          <CamoList
            damascusPercent={damascusPercent}
            setDamascusPercent={setDamascusPercent}
          />
        </div>

        <div>
          <h1>Man-O-War</h1>
          <img src="https://i.imgur.com/Y8AYudI.jpg" alt="Man-O-War" />
          <CamoList
            damascusPercent={damascusPercent}
            setDamascusPercent={setDamascusPercent}
          />
        </div>

        <div>
          <h1>CR-56 AMAX</h1>
          <img src="https://i.imgur.com/3ZWIfZA.jpg" alt="CR-56 AMAX" />
          <CamoList
            damascusPercent={damascusPercent}
            setDamascusPercent={setDamascusPercent}
          />
        </div>

        <div>
          <h1>AS VAL</h1>
          <img src="https://i.imgur.com/6mzUd8F.jpg" alt="AS VAL" />
          <CamoList
            damascusPercent={damascusPercent}
            setDamascusPercent={setDamascusPercent}
          />
        </div>

        <div>
          <h1>Swordfish</h1>
          <img src="https://i.imgur.com/pI8GQ6G.jpg" alt="Swordfish" />
          <CamoList
            damascusPercent={damascusPercent}
            setDamascusPercent={setDamascusPercent}
          />
        </div>

        <div>
          <h1>HVK-30</h1>
          <img src="https://i.imgur.com/pCJHS2J.jpg" alt="HVK-30" />
          <CamoList
            damascusPercent={damascusPercent}
            setDamascusPercent={setDamascusPercent}
          />
        </div>

        <div>
          <h1>Peacekeeper MK2</h1>
          <img src="https://i.imgur.com/joXdWda.jpg" alt="Peacekeeper MK2" />
          <CamoList
            damascusPercent={damascusPercent}
            setDamascusPercent={setDamascusPercent}
          />
        </div>

        <div>
          <h1>FR .556</h1>
          <img src="https://i.imgur.com/zn8pshJ.jpg" alt="FR .556" />
          <CamoList
            damascusPercent={damascusPercent}
            setDamascusPercent={setDamascusPercent}
          />
        </div>

        <div>
          <h1>Oden</h1>
          <img src="https://i.imgur.com/Iupg5eL.jpg" alt="Oden" />
          <CamoList
            damascusPercent={damascusPercent}
            setDamascusPercent={setDamascusPercent}
          />
        </div>

        <div>
          <h1>ICR-1</h1>
          <img src="https://i.imgur.com/aJNh1Kb.jpg" alt="ICR-1" />
          <CamoList
            damascusPercent={damascusPercent}
            setDamascusPercent={setDamascusPercent}
          />
        </div>

        <div>
          <h1>HBRa3</h1>
          <img src="https://i.imgur.com/0Imj29v.jpg" alt="HBRa3" />
          <CamoList
            damascusPercent={damascusPercent}
            setDamascusPercent={setDamascusPercent}
          />
        </div>

        <div>
          <h1>DR-H</h1>
          <img src="https://i.imgur.com/QE8KvoQ.jpg" alt="DR-H" />
          <CamoList
            damascusPercent={damascusPercent}
            setDamascusPercent={setDamascusPercent}
          />
        </div>
      </div>
    </>
  );
}

CamoList.jsx

import { useState, useEffect, useContext } from "react";
import { FaCheck } from "react-icons/fa";
import React from "react";
import { useGetCompletionData } from "../../hooks/getInfo";
import { damascusProgress } from "../../damascusContext";

export default function CamoList({ damascusPercent, setDamascusPercent }) {
  const {
    goldIsActive,
    setGoldActive,
    totalCamo,
    setTotalCamo,
    sandIsActive,
    handleSandClick,
    handleDragonClick,
    dragonIsActive,
    splinterIsActive,
    handleSplinterClick,
    tigerIsActive,
    handleTigerClick,
    handleReptileClick,
    reptileIsActive,
    jungleIsActive,
    handleJungleClick,
  } = useGetCompletionData();

  let { setCount } = useContext(damascusProgress);

  useEffect(() => {
    if (totalCamo === 6) {
      setGoldActive((current) => !current);
      setDamascusPercent((prev) => prev + 1);
      setTotalCamo((prev) => prev + 1);
      setCount((prev) => prev + 4.8);
      updateFill();
    }

    function updateFill() {
      let number = (damascusPercent / 20) * 100;
      document.documentElement.style.setProperty(
        "--circle-radius",
        `${number}deg`
      );
    }

    updateFill();
  }, [totalCamo]);

  return (
    <div className="collection">
      <p>{damascusPercent}</p>
      <div
        id="sand"
        className={sandIsActive ? "active" : ""}
        onClick={handleSandClick}
      >
        <div className={sandIsActive ? "tooltip-hidden" : "tooltip"}>
          <span className="tooltiptext">Kill 600 enemies</span>
        </div>
        <FaCheck className={sandIsActive ? "checkmarkSand" : "nocheckmark"} />
      </div>
      <div
        id="dragon"
        className={dragonIsActive ? "active" : ""}
        onClick={handleDragonClick}
      >
        <div className={dragonIsActive ? "tooltip-hidden" : "tooltip"}>
          <span className="tooltiptext">Kill 50 enemies with hip fire</span>
        </div>
        <FaCheck
          className={dragonIsActive ? "checkmarkDragon" : "nocheckmark"}
        />
      </div>
      <div
        id="splinter"
        className={splinterIsActive ? "active" : ""}
        onClick={handleSplinterClick}
      >
        <div className={splinterIsActive ? "tooltip-hidden" : "tooltip"}>
          <span className="tooltiptext">Kill 80 enemies at long distance</span>
        </div>
        <FaCheck
          className={splinterIsActive ? "checkmarkSplinter" : "nocheckmark"}
        />
      </div>
      <div
        id="tiger"
        className={tigerIsActive ? "active" : ""}
        onClick={handleTigerClick}
      >
        <div className={tigerIsActive ? "tooltip-hidden" : "tooltip"}>
          <span className="tooltiptext">
            Kill 125 enemies with 5 attachments equipped
          </span>
        </div>
        <FaCheck className={tigerIsActive ? "checkmarkTiger" : "nocheckmark"} />
      </div>
      <div
        id="jungle"
        className={jungleIsActive ? "active" : ""}
        onClick={handleJungleClick}
      >
        <div className={jungleIsActive ? "tooltip-hidden" : "tooltip"}>
          <span className="tooltiptext">Kill 100 enemies with head shots</span>
        </div>
        <FaCheck
          className={jungleIsActive ? "checkmarkJungle" : "nocheckmark"}
        />
      </div>
      <div
        id="reptile"
        className={reptileIsActive ? "active" : ""}
        onClick={handleReptileClick}
      >
        <div className={reptileIsActive ? "tooltip-hidden" : "tooltip"}>
          <span className="tooltiptext">
            Kill 80 enemies with no attachments equipped
          </span>
        </div>
        <FaCheck
          className={reptileIsActive ? "checkmarkReptile" : "nocheckmark"}
        />
      </div>
      <div id="gold" className={goldIsActive ? "gold-active" : ""}>
        <div className={goldIsActive ? "tooltip-hidden" : "tooltip"}>
          <span className="tooltiptext">Unlock all previous camos</span>
        </div>
        <FaCheck className={goldIsActive ? "checkmarkGold" : "nocheckmark"} />
      </div>
      <div id="platinum"></div>
      <div id="demas"></div>
    </div>
  );
}

Link directly to the function in question on CodeSandbox:

https://codesandbox.io/s/practical-gates-rr81j0?file=/src/hooks/getInfo.jsx:2112-2357

Context: I'm trying to make it so double clicking on the picture of the gun sets the camo boxes underneath it to "active". Each hook function for each box works individually, but when called together in a function nothing happens. Both console.log()'s execute, but not the functions in between them. I was under the impression that calling each "handle${Camo}Click" function in a separate function would work fine, but it doesn't. I don't know what to search to start figuring out the mechanics of why this happening. If anyone could point me in the right direction that would be very much appreciated.

Drew Reese
  • 165,259
  • 14
  • 153
  • 181
Eric Andre
  • 204
  • 2
  • 9
  • Isn't that what I want though? I want the code to identify the current state value, and perform an action based on that state value? Either setting or removing the action class? – Eric Andre Aug 03 '22 at 23:44
  • when you click each camo box it sets the css to active. I just want to use the same onClicks I used for each camo box all at once at the same in the same function to activate them all on double click. – Eric Andre Aug 04 '22 at 06:11

1 Answers1

0

Issue

The issue is that you've defined a useGetCompletionData hook with its own state, but use several instances of the hook so each instance has and maintains its own state independently.

The setAllCamos callback the the ASM10 image is calling is from a different instance of the useGetCompletionData hook that it's related CamoList component is using. In other words, when the image is double-clicked it's updating state the Camolist doesn't have access to.

Solution

I suggest creating a CompletionDataProvider component to wrap individual sets of images and CamoList components so they can share and reference the same state.

Example:

getInfo.jsx

import { createContext, useContext, useState } from "react";

export const CompletionData = createContext({
  goldIsActive: false,
  setGoldActive: () => {},
  totalCamo: 0,
  setTotalCamo: () => {},
  sandIsActive: false,
  handleSandClick: () => {},
  handleDragonClick: () => {},
  dragonIsActive: false,
  splinterIsActive: false,
  handleSplinterClick: () => {},
  tigerIsActive: false,
  handleTigerClick: () => {},
  handleReptileClick: () => {},
  reptileIsActive: false,
  jungleIsActive: false,
  handleJungleClick: () => {},
  setAllCamos: () => {},
});

const CompletionDataProvider = ({ children }) => {
  const [sandIsActive, setSandActive] = useState(false);
  const [dragonIsActive, setDragonActive] = useState(false);
  const [splinterIsActive, setSplinterActive] = useState(false);
  const [tigerIsActive, setTigerActive] = useState(false);
  const [reptileIsActive, setReptileActive] = useState(false);
  const [jungleIsActive, setJungleActive] = useState(false);
  const [totalCamo, setTotalCamo] = useState(0);
  const [goldIsActive, setGoldActive] = useState(false);

  const handleSandClick = () => {
    // ️ toggle isActive state on click
    setSandActive((current) => !current);
    if (sandIsActive) {
      setTotalCamo((prev) => prev - 1);
    } else {
      setTotalCamo((prev) => prev + 1);
    }
  };

  const handleDragonClick = () => {
    // ️ toggle isActive state on click
    setDragonActive((current) => !current);
    if (dragonIsActive) {
      setTotalCamo((prev) => prev - 1);
    } else {
      setTotalCamo((prev) => prev + 1);
    }
  };

  const handleSplinterClick = () => {
    // ️ toggle isActive state on click
    setSplinterActive((current) => !current);
    if (splinterIsActive) {
      setTotalCamo((prev) => prev - 1);
    } else {
      setTotalCamo((prev) => prev + 1);
    }
  };

  const handleTigerClick = () => {
    // ️ toggle isActive state on click
    setTigerActive((current) => !current);
    if (tigerIsActive) {
      setTotalCamo((prev) => prev - 1);
    } else {
      setTotalCamo((prev) => prev + 1);
    }
  };

  const handleReptileClick = () => {
    // ️ toggle isActive state on click
    setReptileActive((current) => !current);
    if (reptileIsActive) {
      setTotalCamo((prev) => prev - 1);
    } else {
      setTotalCamo((prev) => prev + 1);
    }
  };

  const handleJungleClick = () => {
    // ️ toggle isActive state on click
    setJungleActive((current) => !current);
    if (jungleIsActive) {
      setTotalCamo((prev) => prev - 1);
    } else {
      setTotalCamo((prev) => prev + 1);
    }
  };

  const setAllCamos = () => {
    handleSandClick();
    handleDragonClick();
    handleSplinterClick();
    handleTigerClick();
    handleJungleClick();
  };

  const value = {
    goldIsActive,
    setGoldActive,
    totalCamo,
    setTotalCamo,
    sandIsActive,
    handleSandClick,
    handleDragonClick,
    dragonIsActive,
    splinterIsActive,
    handleSplinterClick,
    tigerIsActive,
    handleTigerClick,
    handleReptileClick,
    reptileIsActive,
    jungleIsActive,
    handleJungleClick,
    setAllCamos
  };

  return (
    <CompletionData.Provider {...{ value }}>
      {children}
    </CompletionData.Provider>
  );
};

export const useGetCompletionData = () => useContext(CompletionData);

export default CompletionDataProvider;

AR_list.jsx

Wrap the image and CamoList component "pairs" in the imported CompletionDataProvider and use CompletionData.Consumer to access the setAllCamos callback for the image click handler.

import React from "react";
import CamoList from "../Completion/CamoList";
import { useState } from "react";
import CompletionDataProvider, { CompletionData } from "../../hooks/getInfo";

export default function AR_LIST() {
  const [damascusPercent, setDamascusPercent] = useState(0);

  return (
    <>
      <h1>Assault Rifle</h1>
      <div className="gun-grid">
        <CompletionDataProvider>
          <div>
            <h1>ASM10</h1>
            <CompletionData.Consumer>
              {({ setAllCamos }) => (
                <img
                  src="https://i.imgur.com/4rk88oj.jpg"
                  alt="ASM10"
                  onDoubleClick={setAllCamos}
                />
              )}
            </CompletionData.Consumer>
            <CamoList
              damascusPercent={damascusPercent}
              setDamascusPercent={setDamascusPercent}
            />
          </div>
        </CompletionDataProvider>

        ...
      </div>
    </>
  );
}

Edit what-is-preventing-this-function-from-executing-the-hooks-inside-of-it-what-abo

Drew Reese
  • 165,259
  • 14
  • 153
  • 181