Как запустить функцию setState в react из дочернего компонента в родительский компонент с данными по нажатию кнопки

#javascript #reactjs #function #components

#javascript #reactjs #функция #Компоненты

Вопрос:

У меня есть родительская компонентная сеть с именем FormLeadBuilderEdit, и именно с помощью useState я передаю функцию setState (setCards в моем случае) в мою дочернюю компонентную сеть с именем Card. По какой-то причине в дочернем компоненте, когда я вызываю setCard («vale»), состояние не обновляется. Поэтому я не уверен, что я делаю неправильно.

Любая помощь была бы отличной

Спасибо

Компонент FormLeadBuilderEdit

 import React, { useState, useEffect } from "react";
import { Card } from "./Card";

const FormLeadBuilderEdit = ({ params }) => {

  const inputs = [
    {
      inputType: "shortText",
      uniId: Random.id(),
      label: "First Name:",
      value: "Kanye",
    },
    {
      inputType: "phoneNumber",
      uniId: Random.id(),
      label: "Cell Phone Number",
      value: "2813348004",
    },
    {
      inputType: "email",
      uniId: Random.id(),
      label: "Work Email",
      value: "kanye@usa.gov",
    },
    {
      inputType: "address",
      uniId: Random.id(),
      label: "Home Address",
      value: "123 White House Avenue",
    },
    {
      inputType: "multipleChoice",
      uniId: Random.id(),
      label: "Preferred Method of Contact",
      value: "2813348004",
      multipleChoice: {
        uniId: Random.id(),
        options: [
          {
            uniId: Random.id(),
            label: "Email",
            checked: false,
          },
          {
            uniId: Random.id(),
            label: "Cell Phone",
            checked: false,
          },
        ],
      },
    },
    {
      inputType: "dropDown",
      uniId: Random.id(),
      label: "How did you find us?",
      value: "2813348004",
      dropDown: {
        uniId: Random.id(),
        options: [
          {
            uniId: Random.id(),
            label: "Google",
          },
          {
            uniId: Random.id(),
            label: "Referral",
          },
        ],
      },
    },
  ];
  const [cards, setCards] = useState([]);

  setCards(inputs)

  return (
    <>
      <Card
        key={card.uniId   index}
        index={index}
        id={card.uniId}
        input={card}
        setCards={setCards}
        params={params}
        cards={cards}
      />
    </>
  );
};

export default FormLeadBuilderEdit;
  

Компонент корзины

 import React, { useRef } from "react";
import { Random } from "meteor/random";

export const Card = ({ setCards, cards }) => {
    const addOption = () => {
    const newCards = cards;

    newCards.map((card) => {
      if (card.inputType === "multipleChoice") {
        card.multipleChoice.options.push({
          uniId: Random.id(),
          label: "test",
          checked: false,
        });
      }
    });

    console.log(newCards);

    setCards(newCards);

  return (
    <>
      <button onClick={addOption} type="button">
        Add Option
      </button>
    </>
  );
};
  

Комментарии:

1. map возвращает новую копию массива. Попробуйте это const newCard = ...your card map code; setCards(newCard)

2. Согласно вашей логике, cards.map всегда будет возвращать пустой массив, который вы на самом деле не добавляете. никакой опции.

Ответ №1:

React использует ссылку на переменную как способ узнать, какое состояние было изменено, а затем запускает повторный рендеринг.

Итак, первое, что вы хотели бы знать о состоянии, это то, что «Не изменять состояние напрямую».
Ссылка: https://reactjs.org/docs/state-and-lifecycle.html#using-state-correctly

Вместо этого создайте новое состояние, содержащее изменения (с другой ссылкой на переменную) :

 const addOption = () => {
    const newCards = cards.map((card) => {
      if (card.inputType === "multipleChoice") {          
        const newOption = {
          uniId: Random.id(),
          label: "test",
          checked: false,
        };
        card.multipleChoice.options = [...card.multipleChoice.options, newOption];
      }
      return card;
    });

    setCards(newCards);
    // setCards(cards); <- this refer to the current `cards` which will not trigger re-render
  };
  

Комментарии:

1. Я следовал вашему шаблону, но он регистрировался в консоли undefined, поэтому я слегка изменил его, как показано в моем вопросе выше, но мое изменение состояния по-прежнему не перезаписывает мою компонентную сеть

2. Привет, я отредактировал ответ. Я предполагаю, что вы хотите запустить повторный рендеринг массива параметров. Также отмечено, что map функция должна что-то возвращать

Ответ №2:

Как указал один из пользователей, вы передаете пустой cards массив, над которым выполняете map операцию, которая, что неудивительно, возвращает сам пустой массив, следовательно, вы не получаете никаких изменений состояния.

Логика передачи setCards правильная.

Вот небольшой пример, в котором происходят изменения состояния, а также показаны.

 
import React, { useState } from "react";

const App = () => {
  const [cards, setCards] = useState([]);

  return (
    <>
      <Card
        setCards={setCards}
        cards={cards}
      />
      <p>{cards.toString()}</p>
    </>
  );
};



const Card = ({ setCards, cards }) => {
  const addOption = () => {
    setCards(["1","2"]);
  };

  return (
    <>
      <button onClick={addOption} type="button">
        Add Option
      </button>
    </>
  );
};

export default App;

  

Скриншот:

изменение состояния дочернего компонента

Ссылка на Codesandbox

Комментарии:

1. Извините, мой фактический код был намного больше, поэтому я не показал, где я изначально установил состояние. Я добавил свои изменения, описанные выше, он будет регистрировать правильные (новые карточки), но изменение состояния никогда не перезапускает страницу

2. если возможно, рассмотрите возможность публикации этого проекта в CodeSandbox и поделитесь ссылкой

3. хорошо, я попробую, но это проект meteor, поэтому у него есть некоторые зависимости, которые я не уверен, что смогу настроить