Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

96
Visualizações
Array of components doesn't update when props change

Codesandbox link

I have two components, a Parent and a Child. The Parent components keeps a list of Children in state and renders it using the map method.

The parent:

import { useState } from "react";
import Child from "./Child";

export default function Parent(){
    const [counter, setCounter] = useState(0)
    const [childKey, setChildKey] = useState(0);
    const [children, setChildren] = useState([]);

    function addChild(){
        setChildren([...children, <Child counter={counter} index={childKey}/>]);
        setChildKey(childKey + 1);
    }

    return (
        <>
            <h2>The parent component</h2>
            <p>The counter is set to {counter}</p>
            <p><button onClick={() => {setCounter(counter + 1)}}>Increment</button></p>
            <p><button onClick={addChild}>Add child</button></p>

            {children.map((c, i) => {
                return (
                        <div key={i}>{c}</div>
                    );
            })}
            
        </>
    );
}

The Child:

export default function Child({counter, index}){
    return (
        <>
            <p>Child {index}: the counter is set to {counter}</p>
        </>
    );
}

Clicking the "add child" button adds an child to the children array.

Clicking the "increment" button updates the counter on the parent, but the counter in the children does not change.

Is there a way to re-render the children when the counter increments? (while preferably keeping the children in an array)

Codesandbox link

almost 4 years ago · Santiago Trujillo
3 Respostas
Responde à pergunta

0

setChildren([...children, <Child counter={counter} index={childKey}/>]);

Don't put elements into state. It makes it really easy to have bugs like the one you're having right now. You've effectively "locked in" what the props to the child are, so changes to the counter will not take effect.

Instead, just store the minimal data that's needed to create the elements, and then create those elements during rendering. In your case, i think you just need a number saying how many children to render. Conveniently, you already have that in childKey, so i recommend:

export default function Parent(){
    const [counter, setCounter] = useState(0)
    const [childKey, setChildKey] = useState(0);

    const children = [];
    for (let i = 1; i <= childKey; i++) {
      children.push((
        <div key={i}>
          <Child counter={counter} index={i} />
        </div>
      ));
    }

    function addChild(){
        setChildKey(childKey + 1);
    }

    return (
        <>
            <h2>The parent component</h2>
            <p>The counter is set to {counter}</p>
            <p><button onClick={() => {setCounter(counter + 1)}}>Increment</button></p>
            <p><button onClick={addChild}>Add child</button></p>

            {children}
            
        </>
    );
}

Maybe childKey could be renamed to childCount.

almost 4 years ago · Santiago Trujillo Relatório

0

When you do:

setChildren([...children, <Child counter={counter} index={childKey}/>]);

You tell React to add <Child counter={counter} index={childKey}/> element to the children state. It creates an element with the props counter and childKey with the values that they have at the time you add them to the state. Re-rendering these elements with a different value for childKey will have no impact.

Depending on what you want to do, there are many solutions. If you want to render Child with the value of counter at the time of re-render I would do something like this:

export default function Parent(){
    const [counter, setCounter] = useState(0)
    const [childKey, setChildKey] = useState(0);
    const [children, setChildren] = useState([]);

    function addChild(){
        setChildren([...children, ({ counter }) => <Child counter={counter} index={childKey}/>]);
        setChildKey(childKey + 1);
    }

    return (
        <>
            <h2>The parent component</h2>
            <p>The counter is set to {counter}</p>
            <p><button onClick={() => {setCounter(counter + 1)}}>Increment</button></p>
            <p><button onClick={addChild}>Add child</button></p>

            {children.map((childFn, i) => {
                return (
                        <div key={i}>{childFn({ counter })}</div>
                    );
            })}
            
        </>
    );
}

Or may be simpler (and less error prone):

export default function Parent(){
    const [counter, setCounter] = useState(0)
    const [childKey, setChildKey] = useState(0);
    const [children, setChildren] = useState([]);

    function addChild(){
        setChildren([...children, childKey]);
        setChildKey(childKey + 1);
    }

    return (
        <>
            <h2>The parent component</h2>
            <p>The counter is set to {counter}</p>
            <p><button onClick={() => {setCounter(counter + 1)}}>Increment</button></p>
            <p><button onClick={addChild}>Add child</button></p>

            {children.map((childKey, i) => {
                return (
                        <div key={i}><Child counter={counter} index={childKey} /></div>
                    );
            })}
            
        </>
    );
}
almost 4 years ago · Santiago Trujillo Relatório

0

Yes like other answers keeping components in state is not a good idea - well explained by Nicholas above

Same answer but different style of rendering 😛

Just updated the Parent.js as below

import { useState } from "react";
import Child from "./Child";

export default function Parent() {
  const [counter, setCounter] = useState(0);
  const [childKey, setChildKey] = useState(0);

  function addChild() {
    setChildKey(childKey + 1);
  }

  return (
    <>
      <h2>The parent component</h2>
      <p>The counter is set to {counter}</p>
      <p>
        <button
          onClick={() => {
            setCounter(counter + 1);
          }}
        >
          Increment
        </button>
      </p>
      <p>
        <button onClick={addChild}>Add child</button>
      </p>
      {/* create an array of length of childKey number */}
      {Array.from({ length: childKey }, (_, i) => {
        return <Child key={i} counter={counter} index={i} />;
      })}
    </>
  );
}
almost 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda