Как я могу изменить состояние массивов с помощью хуков? - PullRequest
0 голосов
/ 08 апреля 2019

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

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

  function sessionToState(session) {
    let formattedArray = []
    for (let i = 0; i < session.length; i++) {
      formattedArray.push({ url: session[i] })
      setLinksArray([...linksArray, formattedArray[i]])
    }
  }

  // --------------------------------------------------------

  return (
    <div>
      <form
        method="post"
        onSubmit={async e => {
          e.preventDefault()

          const session = await getURLs({ populate: true })

          sessionToState(session)

          await createGroup()

Мне было интересно, есть ли какие-то большие вещи, которые мне не хватает, или, может быть, какие-то отличные советы и рекомендации по работес массивами с использованием крючков.Если вам нужна дополнительная информация, не стесняйтесь спрашивать.Спасибо.

Ответы [ 3 ]

2 голосов
/ 08 апреля 2019

Производительность не стоит называть setState каждую итерацию. Вы должны установить состояние с окончательным массивом.

const sessionToState = (session) => {
  setLinksArray(
   session.map(sessionItem => ({url: sessionItem}))
  );
}

... или если вы хотите сохранить старые элементы, вы должны сделать это с помощью функции внутри setState ...

const sessionToState = (session) => {
  setLinksArray(oldState => [
   ...oldState,
   ...session.map(sessionItem => ({url: sessionItem}))
  ]);
}
2 голосов
/ 08 апреля 2019

При вызове установщика состояния из вызовов вложенных функций следует использовать форму функционального обновления setState. В вашем случае это будет:

setLinksArray(linksArray => [...linksArray, formattedArray[i]])

Не совсем ясно, с какими проблемами вы сталкиваетесь, но приведенное выше исправление спасет вас от неожиданного состояния linksArray.

Также это относится к любому состоянию, а не только к массивам.

1 голос
/ 08 апреля 2019

Мне было интересно, есть ли какие-то большие вещи, которые мне не хватает

TLDR: setLinksArray не обновляет linksArray в текущем рендере, но в следующем рендере.


При условии, что переменные инициализируются следующим образом:

const [linksArray, setLinksArray] = useState([])

Подсказка в ключевом слове const, linksArray - это константа в пределах 1рендеринга (и этот факт не изменится с let, потому что это просто, как работает useState).

Идея setLinksArray() состоит в том, чтобы сделать следующее постоянное значение в следующем рендере.

Таким образом, цикл for будет похож на:

setLinksArray([...[], session0])
setLinksArray([...[], session1])
setLinksArray([...[], session2])

, и вы получите linksArray = [session2] в следующем рендере.

Лучший способсохранить разумность - это вызывать любую функцию setState только один раз для каждого состояния в рендере (хотя вы можете иметь несколько состояний), самое маленькое изменение в вашем коде:

function sessionToState(session) {
  let formattedArray = []
  for (let i = 0; i < session.length; i++) {
    formattedArray.push({ url: session[i] })
  }
  setLinksArray(formattedArray)
}

Кроме того, если вам нужно выполнитьпобочный эффект (как вызов API) после того, как все функции setState выполнят свою работу, т.е. после рендеринга NEXT вам потребуется useEffect:

useEffect(() => {
    ...do something with updated linksArray...
}, [linksArray])

Глубокое погружение см. https://overreacted.io/react-as-a-ui-runtime

...