'Setting state in useEffect and then passing as a prop

Not exactly sure why this isn't working I want to set state based on a passed in prop and then pass the state as a prop, but it doesn't work when I use it in a useEffect. I had originally just used a regular function to do this and it worked, but trying to clean up code and it doesn't seem to work.

const Picker = ({choices, activeValue}) => {
  const [clickIndex, setClickIndex] = useState(null);

  useEffect(() => {
    choices.forEach((choice, index) => {
      if (activeValue && choice === activeValue) {
        setClickIndex(index);
      }
    });
  }, [choices, activeValue]);

  return (
      <Options
        clickedIndex={clickIndex}
      />
  );
  
}

Then in the Options component I set state based on clickedIndex

const [state, setState] = useState({ [clickedIndex]: "clicked" });

The state always ends up as {null: "clicked"} in the Options component. Even though the props shows to be 2.

Before I had done this, just invoking a function for the Picker component instead of useEffect and it worked.

EDIT: Fixed getInitialClicked implementation

const getInitialClicked = () => {
    let clickIndex = null;
    choices.forEach((choice, index) => {
      if (activeValue && choice === activeValue) {
        clickIndex = index;
      }
    }
    return clickIndex;
}

  return (
      <Options
        clickedIndex={getInitialClicked()}
      />
  );

What am I not understanding with this? Is is bad form to do it the function way or does it not actually matter?



Solution 1:[1]

The value passed to useState only gets checked by React when the component mounts. On further re-renders, the value is ignored, and instead React uses the value that component has in state (passed into it on mount).

A good way to deal with this sort of thing is to not duplicate state between components, because keeping them in sync is a pain and can lead to confusing code. In the Options, remove

const [state, setState] = useState({ [clickedIndex]: "clicked" });

and instead just reference the clickedIndex prop. If you also need an object for rendering or something, construct the object in the main block of the Options function:

const clickedIndexObject = { [clickedIndex]: 'clicked' };

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1