GithubHelp home page GithubHelp logo

Comments (9)

alulamoke avatar alulamoke commented on July 17, 2024 2

actually you don't have to use hooks, it works perfectly like this 👇.

export function List({ items = [] }) { return <div>Length: {items.length}</div>; }

from react.

mkozachok avatar mkozachok commented on July 17, 2024 1

but this code works correct

const defaultEmptyArray = []; 

export function List({ items = defaultEmptyArray }) {
  const [itemsState, setItemState] = useState([]);

  useEffect(() => {
    setItemState(items); // this line starts infinite loop
  }, [items]);

  return <div>Length: {itemsState.length}</div>;
}

from react.

chirag-droid avatar chirag-droid commented on July 17, 2024 1

I don't think this is a bug. This happens because you are triggering an update via useEffect which depends on items. But this items is recreated on each rerender. Either set defaultProps property or use const.

https://react.dev/learn/you-might-not-need-an-effect

export function List({ items = defaultEmptyArray }) {
  const [itemsState, setItemState] = useState(items);
  return <div>Length: {itemsState.length}</div>;
}

or

export function List({ items = defaultEmptyArray }) {
  return <div>Length: {items.length}</div>;
}

from react.

mkozachok avatar mkozachok commented on July 17, 2024 1

I don't think this is a bug. This happens because you are triggering an update via useEffect which depends on items. But this items is recreated on each rerender. Either set defaultProps property or use const.

https://react.dev/learn/you-might-not-need-an-effect

export function List({ items = defaultEmptyArray }) {
  const [itemsState, setItemState] = useState(items);
  return <div>Length: {itemsState.length}</div>;
}

or

export function List({ items = defaultEmptyArray }) {
  return <div>Length: {items.length}</div>;
}

I have more complex code in my project. It's just simple representation of issue.
I do not see any warning about this in docs. So if is bad practise or limitation - it must be mentioned.

from react.

bk7312 avatar bk7312 commented on July 17, 2024

I think the issue is that [] !== [] but defaultEmptyArray === defaultEmptyArray.

When you call <List /> without specifying the items prop, react will set items = [] every time it re-renders, which will trigger useEffect to always run since the value of items will always be different from the previous render, i.e. [] !== [].

from react.

chirag-droid avatar chirag-droid commented on July 17, 2024

Yeah, i think the documentation is lacking about use of defaultProps or const.

And this is confusing for people because of how javascript works.

from react.

Pratish10 avatar Pratish10 commented on July 17, 2024

The set updating state is causing infinite loop because it is taking reference of the array.

In JavaScript, when you create a new array, even if the content is the same, it results in a new reference. React uses reference comparison to determine whether the state or props have changed, and if the references are different, it assumes a change has occurred.

So items coming from props is not equal to items in useEffect

By using JSON.stringify to compare the contents, you are checking for changes at the content level, not just the reference level.

import { useEffect, useState } from "react";

export function List({ items = [] }) {
  const [itemsState, setItemState] = useState([]);

  useEffect(() => {
    if (JSON.stringify(items) !== JSON.stringify(itemsState)) {
      setItemState(items);
    }
  }, [items]);

  return <div>Length: {itemsState.length}</div>;
}

from react.

chirag-droid avatar chirag-droid commented on July 17, 2024

using JSON.stringify is very expensive and bad.

Simplify specify defaultProps for your components or reference a const variable.

from react.

rickhanlonii avatar rickhanlonii commented on July 17, 2024

As others said, the reason for the loop is that items = [] creates a new array for items every render. Because the array is new, the effect thinks it's different, and the effect is triggered. The short fix is to move the default value to a module level definition, so it's the same array for every render that uses the default value, as @mkozachok said.

However, this pattern is an example of when you don't need to use an effect. Instead of an effect, to sync props to state, you can call setState in render using the pattern described in Adjusting Some State When a Prop Changes.

from react.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.