Почему setstate usestate не срабатывает
Перейти к содержимому

Почему setstate usestate не срабатывает

  • автор:

Не работает useState

введите сюда описание изображения

Всем привет! Несколько дней не могу понять в чем проблема. Пишу ToDo лист, в котором должна быть функция удаления некоторых элементов по нажатию кнопки. Пишу useState, и он не удаляет. Почему то не работает setState. Если вывожу в консоль copy, то показывает что элементы массива удаляются, но если же вывожу сам st, то он вообще не меняется. Вот сам код:

const data = [ < title: "Finish essay collaboration", isCompleted: false, id: 1 >, < title: "Read next chapter of the book", isCompleted: false, id: 2 >, < title: "Send the finished assignment", isCompleted: false, id: 3 >,] const ToDo = ()=>< const [st, setSt] = useState(data) const del = (id)=> < const copy = [. st] const current = copy.filter(t=>t.id !==id) setSt(current) console.log(current) > 

Почему setState не меняет состояние?

notiv-nt

Весь твой код в принципе неправильный. Я, конечно, не знаю, что за компонент Form, но предполагаю, что там тоже будут ошибки. Возможно ты gettingWeather передаешь в onSubmit и там получаешь данные погоды, которые в итоге все равно никуда не идут — потому что код не дописан, но ок, вопрос вообще не про это.

State в React-компоненте это не просто переменная, которую можно создать с помощью const или let. Есть два варианта создания компонента и хранение стейта — это классовый и функциональные подходы:

class App extends React.Component < // на самом деле тоже старый подход constructor() < this.state = < city: "Какой-то город" >> // babel из "коробки" давно уже поддерживает такой вариант state = < city: "Какой-то город" >>
const App = () =>

Чтобы поменять значение стейт надо вызвать функцию в которой ты меняешь стейт. То есть в твоем случае handleClick должен находить в блоке App, а не gettingWeather и вызываться например при клике на кнопку где-то

P.S. А, ну и у App в this нет setState, который ты вызываешь из handleClick. Короче ты смешал все виды взаимодействия с состоянием в одной функции. Советую почитать сначала туториал реакта на оф сайте, а потом что-то делать методом тыка.

Почему не работает useState при клике?

Kentavr16

А в тайм-ауте не меняется из-за замыкания. Это константа. Она никогда не поменяется в замыкании. Никогда.

Ответ написан более двух лет назад
Нравится 1 3 комментария
Сергей @DaveGarrow Автор вопроса

А можете привести пример как использовать это с useEffect? Ну т е по клику я хочу получить chosenPicture и использовать его дальше в коде. Как я понял его можно получить только в useEffect, но как это сделать не пойму.

CriticalError

Дмитрий Воробьев @CriticalError
Что за бред?

Он работает. Он асинхронный. В документации про это написано. Если ты хочешь что-то делать с новым значением стейта, то это что-то ты должен делать в useEffect

Получается что без useEffect нельзя использовать измененный state? Интересно почему? Вот документация о useState
где в ней говориться о совместном использовании с useEffect()?

А в тайм-ауте не меняется из-за замыкания. Это константа. Она никогда не поменяется в замыкании. Никогда.

Чувак что ты куришь, дай мне тоже. Посмотри внимательнее

setTimeout(() => < console.log(chosenPicture); >, 5000);

Ты setTimeout константой считаешь?(Тогда почему она вызываеться?)
Или chosenPicture (но разве он ее меняет?)

Получается что без useEffect нельзя использовать измененный state?

Всё верно. Потому что setState асинхронный, да и язык так работает, что нельзя изменить константу

const [state, setState] = useState(0); //^^^^^ – константа, её значение – 0 const onClick = () => < console.log(state) // ^^^^^ – константа её значение – 0 setState(1) // при следующем рендере компонента (и при следующем объявлении константы) значение константы будет равно единице console.log(state) // ^^^^^ – константа, её значение – всё ещё 0 setTimeout(() =>< console.log(state) // ^^^^^ – константа, полученная через замыкание, созданное лексическим контекстом функции onClick, её значение всегда будет 0 >, 10 * 1000 * 1000) > useEffect(() => < // функция будет вызвана при каждом рендере, при условии, что на прошлом рендере значение state отличалось от текущего console.log(state) // ^^^^^ – на первом рендере (до клика) – 0 // на втором рендере (из-за клика изменился стейт, происходит ререндер) – 1 >, [state])
setChosenPicture(fileName); setTimeout(() => < console.log(chosenPicture); >, 5000);

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

const [chosenPicture, setChosenPicture] = useState(''); console.log(chosenPicture) // после обновления стейта в консоль выведется новое значение const handleShowFloatingPicture = (index, fileName, width, height, element) => < setChosenPicture(fileName); setTimeout(() =>< console.log(chosenPicture); // здесь старое значение, потому что функция вызвалась только один раз // и на момент вызова там была пустая строка >, 5000); >

Сделать что-то со значением можно через useEffect:

const [chosenPicture, setChosenPicture] = useState(''); useEffect(() => < if (chosenPicture) < console.log(chosenPicture) >>, [chosenPicture]) // это массив завимостей, useEffect вызывает свой коллбэк каждый раз при изменении завимостей const handleShowFloatingPicture = (index, fileName, width, height, element) =>

Состояние компонента

Метод setState() планирует изменение объекта состояния ( state ) компонента. Когда состояние меняется, компонент рендерится повторно.

Какая разница между state и props ?

props (намеренно сокращённо от англ. «properties» — свойства) и state — это обычные JavaScript-объекты. Несмотря на то, что оба содержат информацию, которая влияет на то, что увидим после рендера, есть существенное различие: props передаётся в компонент (служат как параметры функции), в то время как state находится внутри компонента (по аналогии с переменными, которые объявлены внутри функции).

Несколько полезных ресурсов для дальнейшего изучения, в каких случаях использовать props , а в каких — state :

  • Props vs. State
  • ReactJS: Props vs State

Почему setState даёт неверное значение?

В React как this.props , так и this.state представляют значения, которые уже были отрендерены, например, то, что видите на экране.

Вызовы setState являются асинхронными, поэтому не стоит рассчитывать, что this.state отобразит новое значение мгновенно после вызова setState . Необходимо добавить функцию, которая сработает только после обновления состояния, если нужно получить новое значение, основанное на текущем состоянии (ниже подробный пример).

Пример кода, который не будет работать так, как ожидаем:

incrementCount()  // Примечание: это *не* сработает, как ожидалось. this.setState(count: this.state.count + 1>); > handleSomething()  // Допустим, что `this.state.count` начинается с 0. this.incrementCount(); this.incrementCount(); this.incrementCount(); // Когда React делает последующий рендер компонента, `this.state.count` будет 1, хотя мы ожидаем 3. // Так происходит, потому что функция `incrementCount()` берёт своё значение из `this.state.count`, // но React не обновляет `this.state.count`, пока компонент не отрендерится снова. // Получается, что `incrementCount()` обращается к текущему значению `this.state.count`, а это 0 каждый раз, и добавляет 1. // Как исправить это — разберём ниже! >

Далее перейдём к исправлению указанной проблемы.

Как обновить состояние значениями, которые зависят от текущего состояния?

Нужно добавить функцию вместо объекта к setState , которая будет срабатывать только на самой последней версии состояния (пример ниже).

В чём разница между добавлением объекта или функции к setState ?

Добавление функции даёт вам доступ к текущему состоянию внутри самой функции. Так как setState вызовы «сгруппированы», это помогает связать изменения и гарантирует, что они будут выполняться друг за другом, а не конфликтовать.

incrementCount()  this.setState((state) =>  // Важно: используем `state` вместо `this.state` при обновлении. return count: state.count + 1> >); > handleSomething()  // Возьмём снова для примера, что `this.state.count` начинается с 0. this.incrementCount(); this.incrementCount(); this.incrementCount(); // Если посмотреть на значение `this.state.count` сейчас, это будет по-прежнему 0. // Но когда React отрендерит компонент снова, будет уже 3. >

Когда setState работает асинхронно?

В настоящее время setState работает асинхронно внутри обработчиков событий.

Это даёт гарантию, например, когда Родитель и Ребёнок вызывают setState во время клика, Ребёнок не будет рендериться дважды. Вместо этого React «откладывает» обновление состояния в самый конец событий в браузере. Это помогает сильно повысить производительность больших приложений.

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

Почему React не обновляет this.state синхронно?

Как говорилось ранее, React намеренно «ждёт» пока все компоненты вызовут setState() в своих обработчиках событий прежде чем начать повторный рендер. Это избавляет от ненужных повторных рендеров.

Вы можете задаваться вопросом: почему React не может просто сразу обновить this.state без повторного рендеринга?

На это есть две причины:

  • Это нарушит логику работы props и state , а значит станет причиной многих багов, которые будет сложно исправить.
  • Это сделало бы невозможным реализацию некоторых возможностей, над которыми мы сейчас работаем.

Этот GitHub-комментарий рассматривает конкретные примеры, которые помогут глубже изучить этот вопрос.

Стоит ли использовать такие библиотеки, как Redux или MobX?

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

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *