Метод push в React Hooks (useState)?

Как вставить элемент внутрь массива useState React hook? Это старый метод в состоянии реакции? Или что-то новое?

Например. Пример push-уведомления setState ?

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
232
0
284 931
10
Перейти к ответу Данный вопрос помечен как решенный

Ответы 10

Ответ принят как подходящий

Когда вы используете useState, вы можете получить метод обновления для элемента состояния:

const [theArray, setTheArray] = useState(initialArray);

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

setTheArray(oldArray => [...oldArray, newElement]);

Иногда вы можете обойтись без использования этой формы обратного вызова, если вы Только обновите массив в обработчиках для определенных конкретных пользовательских событий, таких как click (но не как mousemove):

setTheArray([...theArray, newElement]);

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

Живой пример (передача обратного вызова в setTheArray):

const {useState, useCallback} = React;
function Example() {
    const [theArray, setTheArray] = useState([]);
    const addEntryClick = () => {
        setTheArray(oldArray => [...oldArray, `Entry ${oldArray.length}`]);
    };
    return [
        <input type = "button" onClick = {addEntryClick} value = "Add" />,
        <div>{theArray.map(entry =>
          <div>{entry}</div>
        )}
        </div>
    ];
}

ReactDOM.render(
    <Example />,
    document.getElementById("root")
);
<div id = "root"></div>
<script src = "https://cdnjs.cloudflare.com/ajax/libs/react/16.8.1/umd/react.production.min.js"></script>
<script src = "https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.1/umd/react-dom.production.min.js"></script>

Поскольку единственное обновление для theArray есть в событии click (одно из «дискретных» событий), я мог бы обойтись прямым обновлением в addEntry:

const {useState, useCallback} = React;
function Example() {
    const [theArray, setTheArray] = useState([]);
    const addEntryClick = () => {
        setTheArray([...theArray, `Entry ${theArray.length}`]);
    };
    return [
        <input type = "button" onClick = {addEntryClick} value = "Add" />,
        <div>{theArray.map(entry =>
          <div>{entry}</div>
        )}
        </div>
    ];
}

ReactDOM.render(
    <Example />,
    document.getElementById("root")
);
<div id = "root"></div>
<script src = "https://cdnjs.cloudflare.com/ajax/libs/react/16.8.1/umd/react.production.min.js"></script>
<script src = "https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.1/umd/react-dom.production.min.js"></script>

...и попробуйте setTheArray(currentArray => [...currentArray, newElement]), если вышеперечисленное не работает. Скорее всего в useEffect(...theArray..., []) важно понимать, что theArray это константа, поэтому функциональные обновления нужны для значений из будущих рендеров

Aprillion 08.08.2019 21:12

@Aprillion - Не совсем уверен, что ты хочешь сказать этим useEffect примером...?

T.J. Crowder 09.08.2019 10:08

Если useEffect имеет пустой список зависимостей [], он будет выполнен только во время первого рендера. Таким образом, значение theArray внутри эффекта всегда будет initialArray. В ситуациях, когда setTheArray([...initialArray, newElement]) не имеет смысла, а theArray константа всегда будет равна initialValue, необходимы функциональные обновления.

Aprillion 09.08.2019 11:08

@Aprillion - Боюсь, я все еще не понимаю, возможно, я немного туговат. :-) Зачем нужен эффект только со значением массива исходный? (Я имею в виду, что может быть нечастый вариант использования, но...) И даже если вы это сделаете, какое это имеет отношение к вопросу?

T.J. Crowder 09.08.2019 12:36

Привет, @T.J.Crowder, я использую метод обратного вызова для объединения старых данных с новыми при извлечении данных, но по какой-то причине он не работает должным образом, не могли бы вы проверить это, чтобы понять мою проблему?

Oliver D 04.09.2020 13:18

Я изо всех сил пытался добавить некоторую ценность к существующей ценности. Спасибо!

kta 30.07.2021 19:04

Есть ли способ сделать это без накладных расходов на копирование массива каждый раз?

AlwaysLearning 05.11.2021 12:32

@AlwaysLearning - Официально нет. :-) Вы не можете напрямую изменять объекты, находящиеся в состоянии React. С очень, очень тщательное тестирование, который вы повторяете в каждом второстепенном выпуске React, вам может сойти с рук прямое обновление, за которым следует A) вызов forceUpdate (в компоненте класса) или B) изменение какого-либо другого члена состояния (для запуска повторного рендеринга) . Но любой компонент, использующий массив, который оптимизируется, не выполняя повторную визуализацию, когда массив не меняется (memo,...

T.J. Crowder 05.11.2021 12:35

...PureComponent и т. д.) будет сбит с толку. Или вы можете играть в игры с Proxy (где вы заменяете Proxy, а не копируете массив) и предоставлять прокси всему, что его использует. Я не удивлюсь, если это окажется больше накладных расходов, а не меньше, чем просто копирование массива.

T.J. Crowder 05.11.2021 12:37

Точно так же вы делаете это с «нормальным» состоянием в компонентах класса React.

пример:

function App() {
  const [state, setState] = useState([]);

  return (
    <div>
      <p>You clicked {state.join(" and ")}</p>
      //destructuring
      <button onClick = {() => setState([...state, "again"])}>Click me</button>
      //old way
      <button onClick = {() => setState(state.concat("again"))}>Click me</button>
    </div>
  );
}

это будет работать с onClick, но setState(oldState => [...oldState, pushsomething]) - это то, как вы должны это сделать

Cyrus Zei 10.12.2019 13:27

Чтобы немного расшириться, вот несколько распространенных примеров. Начиная с:

const [theArray, setTheArray] = useState(initialArray);
const [theObject, setTheObject] = useState(initialObject);

Вставить элемент в конец массива

setTheArray(prevArray => [...prevArray, newValue])

Нажмите/обновите элемент в конце объекта

setTheObject(prevState => ({ ...prevState, currentOrNewKey: newValue}));

Нажмите/обновите элемент в конце массива объектов

setTheArray(prevState => [...prevState, {currentOrNewKey: newValue}]);

Вставьте элемент в конец объекта массивов

let specificArrayInObject = theObject.array.slice();
specificArrayInObject.push(newValue);
const newObj = { ...theObject, [event.target.name]: specificArrayInObject };
theObject(newObj);

Вот несколько рабочих примеров. https://codesandbox.io/s/reacthooks-push-r991u

Спасибо за все примеры. У меня была проблема именно с вашим Вставьте элемент в конец объекта массивов. Я пробовал так много разных вещей, но просто не мог собрать их воедино.

sdouble 19.01.2020 20:40

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

Henrique Bruno 20.12.2020 08:25

setTheArray([...theArray, newElement]); — самый простой ответ, но будьте осторожны с изменением элементов в массив. Используйте глубокое клонирование элементов массива.

Упомянутое вами глубокое клонирование означает получение как objA. UseState и объединить objA с objB? Так же, как эта ссылка? gist.githubusercontent.com/kahsing/…

Luiey 14.08.2020 12:00

Наиболее рекомендуемый метод — совместное использование функции-оболочки и оператора распространения. Например, если вы инициализировали состояние под названием name вот так,

const [names, setNames] = useState([])

Вы можете нажать на этот массив следующим образом:

setNames(names => [...names, newName])

Надеюсь, это поможет.

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

BlackCetha 09.04.2020 16:43

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

ilke444 13.04.2020 08:44
// Save search term state to React Hooks with spread operator and wrapper function

// Using .concat(), no wrapper function (not recommended)
setSearches(searches.concat(query))

// Using .concat(), wrapper function (recommended)
setSearches(searches => searches.concat(query))

// Spread operator, no wrapper function (not recommended)
setSearches([...searches, query])

// Spread operator, wrapper function (recommended)
setSearches(searches => [...searches, query])

https://medium.com/javascript-in-plain-english/how-to-add-to-an-array-in-react-state-3d08ddb2e1dc

Я попробовал описанные выше методы для помещения объекта в массив объектов в useState, но при использовании Машинопись возникла следующая ошибка:

Type 'TxBacklog[] | undefined' must have a 'Symbol.iterator' method that returns an iterator.ts(2488)

Настройка для tsconfig.json, по-видимому, была правильной:

{
   "compilerOptions": {
   "target": "es6",
   "lib": [
      "dom",
      "dom.iterable",
      "esnext",
      "es6",
],

Этот обходной путь решил проблему (мой пример кода):

Интерфейс:

   interface TxBacklog {
      status: string,
      txHash: string,
   }

Переменная состояния:

    const [txBacklog, setTxBacklog] = React.useState<TxBacklog[]>();

Вставьте новый объект в массив:

    // Define new object to be added
    const newTx = {
       txHash: '0x368eb7269eb88ba86..',
       status: 'pending'
    };
    // Push new object into array
    (txBacklog) 
       ? setTxBacklog(prevState => [ ...prevState!, newTx ])
       : setTxBacklog([newTx]);

если вы хотите нажать после определенного индекса, вы можете сделать следующее:

   const handleAddAfterIndex = index => {
       setTheArray(oldItems => {
            const copyItems = [...oldItems];
            const finalItems = [];
            for (let i = 0; i < copyItems.length; i += 1) {
                if (i === index) {
                    finalItems.push(copyItems[i]);
                    finalItems.push(newItem);
                } else {
                    finalItems.push(copyItems[i]);
                }
            }
            return finalItems;
        });
    };

Вы можете добавить массив данных в конце пользовательского состояния:

  const [vehicleData, setVehicleData] = React.useState<any[]>([]);
  setVehicleData(old => [...old, ...newArrayData]);

Например, ниже вы видите пример аксиом:

  useEffect(() => {
    const fetchData = async () => {
      const result = await axios(
        {
          url: `http://localhost:4000/api/vehicle?page=${page + 1}&pageSize=10`,
          method: 'get',
        }
      );
      setVehicleData(old => [...old, ...result.data.data]);
    };

    fetchData();
  }, [page]);

Создание состояния массива с помощью useState() Во-первых, давайте посмотрим, как использовать хук useState() для создания переменной состояния массива.

import React from "react";

const { useState } = React;

const [myArray, setMyArray] = useState([]);

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

setMyArray(oldArray => [...oldArray, newElement]);

узнать больше

Аргумент типа '(oldArray: { array1: string[]; }) => any[]' нельзя присвоить параметру типа 'SetStateAction<{ array1: string[]; }>'. Тип '(oldArray: { array1: string[]; }) => any[]' не может быть присвоен типу '(prevState: { array1: string[]; }) => { array1: string[]; }'. Свойство 'array1' отсутствует в типе 'any[]', но необходимо в типе '{ array1: string[]; }'.ts(2345)

Suisse 24.09.2021 01:42

Другие вопросы по теме