0

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!

test3r123
  • 37
  • 2
  • 9
  • I don't understand what you're attempting to accomplish with this `useEffect`. Every time `thickness1` changes, you want to set all three state values to `undefined`? Why don't you just set the state values in the `getReq` operation? What's the goal here? – David Mar 28 '22 at 17:55
  • @David The goal here is to use setThickness, setWidth, setLength appropriately. The reason I split it up and not have everything in getReq was just my attempt at seeing what I can do to have the updated states usable. – test3r123 Mar 28 '22 at 17:59
  • After I use setState() they aren't updated, so I was trying to use useEffect() to update the app with new states, if that makes more sense – test3r123 Mar 28 '22 at 18:00

1 Answers1

1

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.

David
  • 208,112
  • 36
  • 198
  • 279
  • Thanks for the suggestion, would you know why my console.log statements are not updated? I guess if I can do something along the lines of ```thickness1 x width1``` and receive an answer, so those states are set but I'm just not seeing them? – test3r123 Mar 28 '22 at 18:10
  • 1
    @test3r123: Because [state updates are asynchronous](https://stackoverflow.com/q/54069253/328193). You don't need to double-check that the state was updated. Setting the state effectively sets the state. And any operations you want to perform on those values at that time (before the re-render) can be performed using the values that you used to update the state. Such as `jsonData.parts_material_thickness` or `jsonData.parts_material_width`, etc. – David Mar 28 '22 at 18:13