Как получить значение onChange в react.js?

avatar
Somi
9 августа 2021 в 06:20
126
3
-1

Я пытаюсь получить значение из onChange, используя setState, но по какой-то причине, когда я пишу текст на input, я получаю сообщение об ошибке, например Axis.map is not a function

Кроме того, я хотел бы удалить Axisданные по отдельности из последнего, используя splice или pop, но всякий раз, когда я нажимаю кнопку удаления, Axis данные исчезают, кроме первого.

Набор элементов


    const SetElements = ({
    ...
    }) => {
      const [Axis, setAxis] = useState([]);

      const AxisHandler = e => {
        setAxis([
          ...Axis,
          {
            label: "",
            data: "",
            backgroundColor: "",
          },
        ]);
      };

      const deleteAxis = () => {
        setAxis(Axis.splice(-1, 1));
      };

      return (
              <>
                <button onClick={AxisHandler}>add Line</button>

                {Axis.length !== 1 && (
                  <button onClick={deleteAxis}>delete Line</button>
                )}
                
                 {Axis.map((element, index) => (
                <>
                  <AppendingAxis
                  
                    Axis={Axis}
                    setAxis={setAxis}
                    element={element}
                    index={index}
                  />
                </>
              ))}
              </>
            )

Добавление оси


    const AppendingAxis = ({
      index,
      setAxis,
      Axis,
    }) => {
      console.log(Axis);
      return (
        <AxisSetting>
          <h4>{index + 2}Y Axis setting</h4>
          <span>
            <input
              placeholder={index + 2 + "setting"}
              type="textarea"
              onChange={e => setAxis((Axis[index].label = e.target.value))}
            />
          </span>

Источник
Muhammad Bilal Bangash
9 августа 2021 в 06:27
1

не могли бы вы поделиться своим кодом в песочнице кода ??

gu mingfeng
9 августа 2021 в 06:47
1

проверьте возврат соединения, в вашем коде соединение возвращает массив последнего элемента

Ответы (3)

avatar
Drew Reese
9 августа 2021 в 06:30
2

Проблема заключается в изменении состояния в компоненте AppendingAxis.

onChange={e => setAxis((Axis[index].label = e.target.value))}

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

onChange={e => setAxis(Axis => Axis.map((el, i) => i === index
  ? {
      ...el,
      label: e.target.value
    }
  : el,
)}

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

SetElements parent

const changeHandler = index => e => {
  const { value } = e.target;
  setAxis(Axis => Axis.map((el, i) => i === index
    ? {
        ...el,
      label: value
      }
    : el,
  );
};

...

<AppendingAxis
  Axis={Axis}
  onChange={changeHandler(index)}
/>

AppendingAxis дочерний

const AppendingAxis = ({ Axis, onChange }) => {
  console.log(Axis);
  return (
    <AxisSetting>
      <h4>{index + 2}Y Axis setting</h4>
      <span>
        <input
          placeholder={index + 2 + "setting"}
          type="textarea"
          onChange={onChange}
        />
      </span>

И для полноты картины ваш обработчик удаления также имеет проблему с мутацией.

const deleteAxis = () => {
  setAxis(Axis.splice(-1, 1));
};

.splice изменяет массив на месте и возвращает массив, содержащий удаленные элементы. Это совершенно противоположно тому, что вы хотите, я думаю. Как правило, вы можете использовать .filter или .slice для создания новых массивов, а не для изменения существующего.

const deleteAxis = () => {
  setAxis(Axis => Axis.slice(0, -1)); // start at 0, end at second to last
};
Sinan Yaman
9 августа 2021 в 06:38
1

Очень нравится способ поверхностного копирования и обновления состояния с помощью одной функции map. Раньше я делал мелкую копию, а потом обновлял отдельно. Начал использовать этот способ, так что спасибо, Дрю! :D

Drew Reese
9 августа 2021 в 06:42
0

@SinanYaman Да, определенно правильный инструмент для работы. Добро пожаловать. :)

Majid M.
9 августа 2021 в 06:43
0

@DrewReese Всегда отвечай лучше всех! Спасибо, что поделились своими знаниями.

avatar
Majid M.
9 августа 2021 в 06:31
1

Ваша проблема в том, что вы неправильно изменяете состояние. Вы должны сделать неглубокую копию состояния. Вы можете изменить AppendingAxis на этот код:

 const AppendingAxis = ({
      index,
      setAxis,
      Axis,
    }) => {
      console.log(Axis);
      const onChange = (e,index)=>{
       let copy = [...Axis];
       copy[index].label = e.target.value; 
       setAxis(copy);
      }
      return (
        <AxisSetting>
          <h4>{index + 2}Y Axis setting</h4>
          <span>
            <input
              placeholder={index + 2 + "setting"}
              type="textarea"
              onChange={e => onChange(e,index))}
            />
          </span>
Sinan Yaman
9 августа 2021 в 06:33
0

Вместо let a = copy.filter((x) => x.index == index)[0]; let itemIndex = copy.indexOf(a); можно использовать let itemIndex = copy.findIndex(x => x.index === index).

Majid M.
9 августа 2021 в 06:35
0

@SinanYaman Спасибо за внимание. Но нам нужен индекс a для обновления state : copy[itemIndex] = a;. Я прав?

Sinan Yaman
9 августа 2021 в 06:37
0

Да, я плохо переименовал переменную. Вы можете просто получить индекс, вообще не нуждаясь в a. Тот же результат, меньше кода :)

Drew Reese
9 августа 2021 в 06:38
0

Зачем вам повторять состояние 3 раза только для того, чтобы скопировать его и обновить определенный индекс? index не является свойством повторяющихся элементов.

Majid M.
9 августа 2021 в 06:42
0

@DrewReese Спасибо за внимание. Пожалуйста, проверьте мой код еще раз и выскажите свое мнение.

Drew Reese
9 августа 2021 в 06:45
0

Ну, вы все еще повторяете его во второй раз с Array.prototype.findIindex, но у вас уже есть это, так как оно передается в функцию. Вы можете просто использовать переданные index и copy[index] = { ...copy[index], label: value } (вам также нужно мелко скопировать элемент ), чтобы сохранить его в одном цикле.

Majid M.
9 августа 2021 в 06:47
0

@DrewReese Большое спасибо. Я научился писать меньше кода, больше мощности! :)

avatar
Ayush Gupta
9 августа 2021 в 06:28
1

Это происходит из-за этой строки:

onChange={e => setAxis((Axis[index].label = e.target.value))}

Создать функцию:

const handleAxisChange = (e, index) => {
    Axis[index].label = e.target.value;
    setAxis(new Array(...Axis));
}

А затем измените набор onChange следующим образом:

onChange={e => handleAxisChange(e, index)}
Sinan Yaman
9 августа 2021 в 06:31
0

Вы все еще мутируете состояние с помощью Axis[index].label = e.target.value. Сначала вы должны его неглубоко скопировать. Правильная идея, но немного некорректное исполнение