3

Say I have a component that gets an array, and I want to do some logic:

const MyComponent = ({ myArray = [] }) => {
  console.log("infinite rendering");
  const [prop, setProp] = useState([])
  useEffect(() => {
    setProp(myArray.map(x => x + 1))
  }, [myArray])

  return <div />
}

https://codesandbox.io/s/x3kq907r5z

The problem is I get an infinite loop.

I can fix the bug by removing the default value ({ myArray }) and checking if array if (Array.isArray(myArray)) setProp(...)

But I'm struggling to understand: What is the best way of doing any sort of manipulation to a prop (array/object/etc) using hooks?

2
  • I don't really get what are you trying to achieve ? Commented Mar 25, 2019 at 15:15
  • Is this what you tried to achieve ? codesandbox.io/s/826v2qn9r0 Commented Mar 25, 2019 at 15:24

2 Answers 2

5

With the way your code is written currently, myArray is a different instance of an empty array on every render. This means that the effect always gets run, as the dependencies have always changed!

This might seem weird, but consider the following piece of code:

const a = [];
const b = [];
console.log(a === b); // false

The simplest fixes for this would be to either move the fallback logic into the effect:

const MyComponent = ({ myArray }) => {
  console.log("infinite rendering");
  const [prop, setProp] = useState([]);
  useEffect(
    () => {
      setProp(myArray ? myArray.map(x => x + 1) : []);
    },
    [myArray]
  );

  return <div />;
};

Or ensure the same empty array always gets used as the default:

const empty = [];
const MyComponent = ({ myArray = empty }) => {
  console.log("infinite rendering");
  const [prop, setProp] = useState([]);
  useEffect(
    () => {
      setProp(myArray.map(x => x + 1));
    },
    [myArray]
  );

  return <div />;
};
Sign up to request clarification or add additional context in comments.

1 Comment

Your answer plus const empty = []; solution went as a life vest after 4 hours fighting React. Thanks.
0

But I'm struggling to understand: What is the best way of doing any sort of manipulation to a prop (array/object/etc) using hooks?

Hooks are great when you are trying manipulate a local state value, not a prop. You define a state with useState(), and you use useEffect() or other event handlers to update the value.

The prop is being changed outside of the component, which triggers the functional component to re-execute. So, to answer your question: you don't manipulate props with hooks. The best you can do is to prevent rendering when props change with useMemo(), but that's a different topic.

Having said that, your example can just become:

const MyComponent = ({ myArray = [] }) => {

    console.log("runs when myArray changes");

    const newArray = myArray.map(x => x + 1);

  return <div />
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.