Управление несколькими состояниями внутри хука

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

const [slides, setSlides] = useState([])
const [currentSlide, setCurrentSlide] = useState(0)
const [tagName, setTagName] = useState([])

Или вот так:

const [states, setStates] = useState({
  slides: [],
  currentSlide: 0,
  tagName: []
})

И если обе или вторая жизнеспособны (честно говоря, я бы предпочел вторую, так как она менее повторяющаяся при вызове useState и ближе к стандартной мета-состоянию), как можно изменить состояния в таком примере? Я ничего не мог найти по этому поводу, поэтому я попробовал следующее:

useEffect(() => {
  Object.entries(Slides).forEach(slide => {
   setStates(prevState => ({ slides: [...prevState.slides, slide[1]] }))
  })

}, [])

И я возился с ним кучу, пытаясь получить приличные результаты, но я не мог заставить его работать должным образом.

Любые идеи о том, что я делаю неправильно? И по какому из этих методов передовой опыт?

Спасибо!


person Nick09    schedule 03.05.2019    source источник
comment
Ссылка на что-то, идея, что угодно очень ценится! Благодарю вас!   -  person Nick09    schedule 03.05.2019
comment
вы хотите обновить только массив слайдов или каждый ключ состояния?   -  person Mayank Shukla    schedule 03.05.2019
comment
на этот раз просто скользит, если у меня есть настройка состояния, подобная второй, где все состояния находятся внутри одного const [states, setStates], есть ли способ обновить только slides или только currentSlide или только tagName по отдельности, ничего не меняя? Точно так же, как метаданные обычного состояния, где вы копируете все внутри состояния, а затем добавляете значения к одному из свойств (в данном случае это, например, слайды).   -  person Nick09    schedule 03.05.2019


Ответы (2)


С точки зрения обновления состояния, первый шаблон очень прост и удобен, потому что каждая функция stateUpdate будет отвечать за обновление одного значения, которое может быть obj/array/int/bool/string. Другое дело, что для доступа к каждому значению состояния (это будет объект) нужно писать states.slides, states.tagName и т.д.

В первом случае обновление состояния будет просто:

// only value in case of int/string/bool
updateState({ [key]: value }) or updateState(value);

Но во втором случае состояние будет объектом с несколькими ключами, поэтому для обновления любого отдельного значения вам нужно скопировать объект, а затем передать обновленное значение ключа. Как это:

updateState({
  ...obj,
  [key]: newValue
})

Чтобы обновить массив слайдов:

updateState(prevState => ({
  ...prevState,
  slides: newArray
}))

Обработка сложного обновления состояния:

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

Например:

const initialState = { slides: [], tagName: [], currentSlide: 0 };

function reducer(state, action) {
  switch (action.type) {
    case 'SLIDES':
      return { ... };
    case 'TAGNAME':
      return { ... };
    case 'CURRENT_SLIDE':
      return { ... }
    default:
      throw new Error();
  }
}

function Counter({initialState}) {
  const [state, dispatch] = useReducer(reducer, initialState);
  ....
}
person Mayank Shukla    schedule 03.05.2019
comment
Я не заметил, что вы обновили свой ответ, я думаю, что это дополнение делает ответ лучшим, поскольку оно охватывает все методы, представляет useReducer, который, кажется, разработан специально для обработки сложной логики и так далее. И я сказал, что меня тоже интересует способ сделать это «по книге», поэтому я приму этот ответ. Несмотря на то, что я все еще немного запутался в отношении, например: case 'SLIDES': return { ... } - в этом конкретном случае мы бы return { slide[1] } или, ну, все, что нам нужно, добавить в прошлое ценности? он также копирует prevState? - person Nick09; 03.05.2019
comment
нет, здесь нам нужно вернуть полный obj, например: return { ...state, [key]: value } вам не нужно беспокоиться о prevState, который будет обрабатываться самим редуктором. - person Mayank Shukla; 03.05.2019
comment
Также, просто для продолжения распространения информации, я пытался использовать этот метод setStates(prevState => ({ ...prevState.states, slides: slide[1] // coming from a forEach })), но он ведет себя не так, как ожидалось (не копирует объект и не добавляет все функции) . Итак, что я сделал, так это удалил prevState: setState({ ...states, slides: slide[1] // again, coming from a forEach that goes though a object }), и это сработало почти идеально, единственная проблема в том, что я не добавляю каждый элемент на слайды, я получаю только последний! Любые идеи для этого? - person Nick09; 03.05.2019
comment
это потому, что каждый раз, когда вы просто сохраняете только один элемент в массиве slides, вам нужно сначала подготовить массив (весь массив с обновленными элементами), затем назначить массив slides: newUpdatedArray, а также выполнить setState вне цикла, в цикле просто подготовьте новый массив. Нам нужно использовать setState только один раз в конце всех вычислений. - person Mayank Shukla; 03.05.2019
comment
Еще один вопрос о редюсере, пожалуйста, в этом случае, когда вы будете использовать forEach для извлечения элементов, которые необходимо вставить один за другим внутри массива slides, который находится внутри объекта states, где именно вы будете вызывать forEach «протолкнуть» указанные предметы внутрь array? Думаю, это, пожалуй, самый сложный сценарий. - person Nick09; 03.05.2019
comment
конечно, рад ответить на все вопросы, в случае без редуктора вы можете сделать так, чтобы в функции обновления setState (используйте блочное тело стрелочной функции вместо краткой), например: setStates(prevState => { /*run the loop here and return obj*/ return { .... } }), а в случае редуктора сделайте это в конкретном типе действия , затем верните окончательный объект. - person Mayank Shukla; 03.05.2019
comment
Хорошо, я не думаю, что мне больше есть что добавить, я признаю, что многое из этого выше моего понимания, но я попросил больше, чтобы все было как можно более полным, и в будущем, если кто-то еще Имея дело с этими вещами, они могут найти здесь некоторое утешение :) При этом я не могу дождаться, чтобы начать экспериментировать со всем этим, чтобы лучше понять и найти решение, которое лучше всего подходит! Еще раз спасибо и удачного кодирования! - person Nick09; 03.05.2019
comment
Вы замечательный человек, и я желаю вам всего наилучшего :D Спасибо! - person Nick09; 03.05.2019

Это правда, что хук useState может стать довольно многословным при работе со сложным объектом состояния. В этом случае вы также можете рассмотреть возможность использования хука useReducer.

Я бы рекомендовал прочитать эту статью о useState и useReducer.

person Arnaud Christ    schedule 03.05.2019
comment
Большое спасибо за ответ! Вы совершенно правы, однако я обнаружил, что лучше сначала принять ответ, в котором освещены все основания, потому что я не единственный человек, который будет использовать эту информацию в будущем :) Еще раз, большое спасибо за вклад! - person Nick09; 03.05.2019