Ben
Ben

Reputation: 3357

React update values only once

I have a newb question :)

I have a modal that opens in React Native with a dropdown select that requires values. I want to calculate the values whenever the modal opens.

let pickupTime; // Set a value that can be overwritten. I'm not using State because I want this value to change whenever I open the modal again.
const pickupTimeOptions = useRef([{ label: "", value: "" }]); // A ref to store the values
useEffect(() => {
  const pickup_hours_today = business.pickup_hours_today; // Array of strings I pass to the modal.
  console.log("pickup_hours_today", pickup_hours_today);        
  const options = pickup_hours_today.map((time) => {
    return {
      label: time,
      value: time,
    };
  });
  pickupTimeOptions.current = options;
}, [business.pickup_hours_today]);
console.log("pickupTimeOptions", pickupTimeOptions); // Let's see if we got it

The problem is that the ref never updates. The log prints this:

pickupTimeOptions Object {
  "current": Array [
    Object {
      "label": "",
      "value": "",
    },
  ],
}
pickup_hours_today Array [
  ... // the string array of hours
]
Should be updating the ref
pickupTimeOptions Object {
  "current": Array [
    Object {
      "label": "",
      "value": "",
    },
  ],
}
pickup_hours_today Array [
  ...
]
Should be updating the ref

What am I doing wrong? Should I handle this differently? I don't mind using state, but when I tried, it kept updating it whenever I selected a different values with the dropdown picker.

Upvotes: 1

Views: 513

Answers (1)

Sohaib
Sohaib

Reputation: 11297

If you look at the order of console logs, it'll explain what's happening.

This is printed first, meaning calculation in useEffect hasn't happened yet

console.log("pickupTimeOptions", pickupTimeOptions); // Let's see if we got it

According to the documentation useEffect is only called after the render. You need to do the calculation before or during the render cycle.

You can use useMemo which is executed during rendering. Refer to the documentation for more details

Your updated code should look something like this

let pickupTime; // Set a value that can be overwritten. I'm not using State because I want this value to change whenever I open the modal again.
const pickupTimeOptions = useMemo(() => {
  const pickup_hours_today = business.pickup_hours_today; // Array of strings I pass to the modal.
  console.log("pickup_hours_today", pickup_hours_today);        
  const options = pickup_hours_today.map((time) => {
    return {
      label: time,
      value: time,
    };
  });
  return options;
}, [business.pickup_hours_today]);
console.log("pickupTimeOptions", pickupTimeOptions); // Let's see if we got it

Upvotes: 1

Related Questions