Функциональный компонент React, обратный вызов useState без использования useEffect

#reactjs #react-hooks #use-effect #use-state #asynccallback

#reactjs #реагирующие хуки #использование-эффект #use-state #asynccallback

Вопрос:

Я довольно новичок в ReactJS и, возможно, либо слишком сложный, либо не планировал его должным образом.

Я столкнулся с проблемой при использовании перехвата useState для отслеживания свойств в моем проекте.

итак, итак

  1. value берется из текстового поля ввода в качестве текста ввода, из-за использования react-hook-form
  2. type затем проверяется, чтобы увидеть, равно ли оно «Доходу» или «расходу»
  3. Если type == "income" тогда просто установите value using setValue без каких-либо изменений, иначе, если type == "expense" тогда *=-1 и установите value using setValue
  4. parseInt() используется с setValue , чтобы убедиться, что значение сохраняется как число
  5. setRecords вызывается для добавления соответствующей информации в record массив объектов.

итак, как вы можете видеть из 5 шагов выше, useState hook setValue и setRecords вызывается один за другим, проблема, с которой я сталкиваюсь на данный момент, заключается в том, что при первоначальном запуске приложения value вместо добавления будет добавляться.

насколько я понимаю, поскольку перехват useState является асинхронным и не возвращает результат немедленно, поэтому к моменту setRecords вызова value все еще имеет тип text вместо number

Я некоторое время искал в Интернете, но не смог найти хорошего способа решить эту проблему, не используя useEffect hook, я пытался использовать useEffect hook, но мне не удалось заставить его работать, пользователю разрешено вводить то же value самое, и приложение все равно должно добавлятьзначение в record массив объектов.

в конце концов, я решил создать новое свойство currentValue и установить его в форме отправки, потому что это не состояние и оно будет обновляться немедленно, ему не придется ждать setValue обновления value состояния.

Есть ли лучший способ обойти эту проблему? или обходной путь в порядке?

 import React, { useEffect, useContext } from "react";
import RecordList from "./RecordList";
import { useForm } from "react-hook-form";
import { BudgetPlannerContext } from "../context/BudgetPlannerContext";

const BudgetPlanner = () => {
  const { register, handleSubmit, errors } = useForm();
  const [
    records,
    setRecords,
    total,
    setTotal,
    type,
    setType,
    value,
    setValue,
    description,
    setDescription,
  ] = useContext(BudgetPlannerContext);

  let currentValue = 0;

  useEffect(() => {
    setTotal(() =>
      records.reduce((acc, curr) => {
        return acc   curr.value;
      }, 0)
    );
  }, [records, setTotal]);

  const onFormSubmit = (data) => {
    if ((type === "Income") amp; (data.value !== 0)) {
      currentValue = parseInt(data.value);
      setValue(parseInt(data.value));
    } else if ((type === "Expense") amp; (data.value !== 0)) {
      currentValue = parseInt((data.value *= -1));
      setValue(parseInt((data.value *= -1)));
    } else {
      return null;
    }
    setDescription(data.description);
    processValue(type, currentValue);
  };

  const processValue = (type, currentValue) => {
    updateRecord(type, currentValue);
    //setValue(0);
    //setDescription("");
    //console.log(records);
  };

  const updateRecord = (type, currentValue) => {
    setRecords((oldRecord) => [
      ...oldRecord,
      {
        type: type,
        value: currentValue,
        description: description,
        id: Math.random() * 1000,
      },
    ]);
  };

  return (
    <div className="ui segment">
      <div className="search-bar ui segment">
        <form className="ui form" onSubmit={handleSubmit(onFormSubmit)}>
          <div className="field">
            <select
              onChange={(e) => setType(e.target.value)}
              name="todos"
              ref={register}
              className="filter-todo"
            >
              <option value="" defaultValue="defaultValue">
                ---
              </option>
              <option value="Income">Income</option>
              <option value="Expense">Expense</option>
            </select>
            <input
              name="description"
              type="text"
              placeholder="Description"
              ref={register}
            />
            <input
              name="value"
              type="number"
              placeholder="Value"
              ref={register}
            />
          </div>
          <div>Total: {total}</div>
          <button type="submit">Submit</button>
        </form>
      </div>
      <RecordList records={records} setRecords={setRecords} />
    </div>
  );
};

export default BudgetPlanner;

  

Ответ №1:

На вашем месте я бы просто передал новое значение в качестве параметра другим вызываемым вами функциям:

 const onFormSubmit = (data) => {
    if (data.value === 0 || (type !== 'Income' amp;amp; type !== 'Expense')) {
        return;
    }
    const newValue = parseInt(data.value) * (type === 'Income' ? 1 : -1);
    setValue(newValue);
    setDescription(data.description);
    processValue(type, newValue);
};
  

Нет необходимости в дополнительной внешней переменной.

Другой вариант — использовать useEffect (или, предпочтительно, useLayoutEffect ) и вызывать processValue при value изменении:

 const onFormSubmit = (data) => {
    if (data.value === 0 || (type !== 'Income' amp;amp; type !== 'Expense')) {
        return;
    }
    const newValue = parseInt(data.value) * (type === 'Income' ? 1 : -1);
    setValue(newValue);
    setDescription(data.description);
};
useLayoutEffect(() => {
    if (value) {
        processValue(type);
    }
}, [value]);
  

и processValue используйте внешнюю value переменную с отслеживанием состояния.

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

1. Спасибо за быстрый ответ, я принял ваше первое предложение по onFormSubmit функции и внес изменения в свой код, теперь он выглядит намного лучше.