Home > Net >  How can i prevent useEffect() from firing up the first time but listening for a state change?
How can i prevent useEffect() from firing up the first time but listening for a state change?

Time:03-29

I'm using react, node express, postgres

I have a react component that is an html table that gets populated from a postgres table.

Here is parent component Materials:

const Materials = () => {
    const [thickness1, setThickness] = useState(0);
    const [width1, setWidth] = useState(0);
    const [length1, setLength] = useState(0);
    const [partTotalDemand, setTotalDemand] = useState(0);
    const [partPlanned, setPlanned] = useState(0);
...

Here is a method in the component that retrieves data

// Material requirements calculation
    const getReq = async (id) => {
        try {
            const response = await fetch(`http://localhost:5000/materials/${id}`, [id])
            const jsonData = await response.json();

            const tempThickness = jsonData.parts_material_thickness
            const tempWidth = jsonData.parts_material_width
            const tempLength = jsonData.parts_material_length
            const tempTotalDemand = jsonData.workorder_total
            const tempPlanned = jsonData.parts_produced

            stateSetter(tempThickness, tempWidth, tempLength)
        } catch (err) {
            console.log(err.message);
        }
    }

I then want to update the states of the global constants:

const stateSetter = (thickness, width, length) => {
        try {
            setThickness(thickness);
            setWidth(width);
            setLength(length);

            console.log(thickness1);
            console.log(width1);
            console.log(length1);

        } catch (err) {
            console.log(err.message)
        }
    }

    useEffect(() => {
        stateSetter();
    }, [thickness1]);

Essentially the getReq() method is supposed to retrieve the information, and then I need to update the states with those values. As I understand I then need to re-render the component so the new states are usable. I attempted to do this via useEffect() but I'm not successful. The idea was to stop getReq() from firing up on the first render, but if the state changes for thickness1/width1/length1 then it should fire up and re-render, help much appreciated!

CodePudding user response:

You're over-complicating this. All you need to do is set the state values:

const getReq = async (id) => {
  try {
    const response = await fetch(`http://localhost:5000/materials/${id}`, [id])
    const jsonData = await response.json();

    // set state values
    setThickness(jsonData.parts_material_thickness);
    setWidth(jsonData.parts_material_width);
    setLength(jsonData.parts_material_length);
    setTotalDemand(jsonData.workorder_total);
    setPlanned(jsonData.parts_produced);
  } catch (err) {
    console.log(err.message);
  }
}

You don't need to manually do anything to re-render the component. It will re-render whenever state is updated. So the "setter" functions being invoked here will trigger that re-render. (All of the state updates will be batched. So the above won't trigger 5 re-renders, just one with the 5 updated state values.)

Where you would use useEffect is when you want to have some logic which responds to a change in a particular state. For example, if you want to show a message every time thickness changes to a negative value, you'd do something like:

useEffect(() => {
  if (thickness < 1) {
    alert('negative thickness!');
  }
}, [thickness]);

But that's not what you're doing here. All you're doing here is setting state values.

  • Related