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

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

  • автор:

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

33remido, тоесть ты не понимаешь в своем коде почему он будет выполняться бесконечно(react остановит это конечно, но все же)?

Решения вопроса 0
Ответы на вопрос 1
Everybody_Lies @Everybody_Lies
первая ссылка в гугле
Попробуйте так

const customHook = () => < let [state, setState] = useState('пустой'); let arr = [1, 2, 3 ]; if(arr.length >1) < setState('полный', () =>< console.log(state) >); > if(arr.length < 1) < setState('пустой') >return /* пустой */ > export default customHook;

Ответ написан более двух лет назад
33remido @33remido Автор вопроса
дело в том что мне прилетает значение в другой компонент, и оно там пустое
Everybody_Lies @Everybody_Lies
33remido, без полной картины тяжело что-то подсказать
33remido @33remido Автор вопроса
Everybody_Lies, как то так
https://gist.github.com/YaroslavRaksha/ce3d5875b92.
Everybody_Lies @Everybody_Lies

33remido, код который вы скинули уходит в infinity loop, потому что setState вызывает ререндер, который снова вызывает customHook, который снова запускает setState .
вообще не очень понятно, что вы хотите и что конкретно у вас не получается

Ваш ответ на вопрос

Войдите, чтобы написать ответ

react

  • React
  • +1 ещё

Почему получаю undefined из стора?

  • 1 подписчик
  • час назад
  • 33 просмотра

Хук useState — JS: React Hooks

Вы уже достаточно изучили React и умеете создавать функциональные компоненты. Если бы сейчас вы решили написать простой функциональный компонент с изменяемым состоянием, у вас получилось бы что-то такое:

const Example = () =>  let count = 0; const incrementCount = () =>  count += 1; >; return ( div> p>Вы нажали count> раз(а)p> button onClick=incrementCount>> Нажми меня button> div> ); >; 

See the Pen Untitled by Hexlet (@hexlet) on CodePen.

В самом компоненте мы видим созданное состояние let count = 0 , а в обработчике клика — уже измененное состояние count += 1 . Но есть одна проблема — при нажатии кнопки число не изменится, потому что компонент отрисовывает изначальное состояние 0 .

Дело в том, что React не видит изменений переменной count . Он отрисовывает компонент в первый раз, потом вызывает функцию компонента и больше ничего не делает. Нужно заставить React повторно вызывать нашу функцию рендера компонента уже с новым состоянием. В этом нам поможет useState() — самый популярный и простой в понимании хук. Именно его мы изучим в этом уроке.

Хук useState() отвечает за работу с состоянием внутри компонента. В отличие от классовых компонентов хук занимается сразу всем: инициализацией, обновлением и доступом к состоянию. Пример вызова:

// Не забываем импортировать import React,  useState > from 'react'; const Example = () =>  // Имена возвращаемых значений выбираются произвольно const [count, setCount] = useState(0); return ( div> p>Вы нажали count> раз(а)p> button onClick=() => setCount(count + 1)>> Нажми меня button> div> ); >; 

useState() принимает на вход начальное состояние и возвращает массив из двух значений: текущего значения состояния и функции, которая обновляет это состояние. Кроме того, что такой код выглядит необычно, еще есть вопросы к его работе. Как мы знаем, компонент, как функция, вызывается на каждую перерисовку. Логично предположить, что значением count всегда будет 0 из-за постоянных вызовов useState() . Как это ни странно, но такого не произойдет. Хуки устроены гораздо хитрее, чем это кажется на первый взгляд. Да, функция useState() действительно вызывается каждый раз при перерисовке, но внутри она знает об этом и учитывает это в работе. Начальное состояние задается ровно один раз и дальше не используется. Само состояние хранится где-то внутри и скрыто от прямого изменения. Единственный способ повлиять на него — вызвать вернувшуюся функцию с передачей нового состояния.

Функцию setCount() можно вызывать в любом месте, например, в коллбеке, как в примере выше, или в другом компоненте, куда эта функция может быть передана. В этом смысле все работает так же, как и в классах.

В отличие от this.setState() , хук useState() не сливает старое состояние с новым:

// Где-то в колбеке setTodos([ text: 'Помыть посуду' >]); // На следующем цикле // Пропало начальное значение console.log(todos); // => [< text: 'Помыть посуду' >] 

Хуки могут использоваться больше одного раза, если это нужно. Мы легко можем создать несколько переменных состояния:

const ExampleWithManyStates = () =>  const [age, setAge] = useState(42); const [schoolName, setSchoolName] = useState('Хекслет'); const [todos, setTodos] = useState([ text: 'Изучить хуки' >]); // . >; 

Сколько создавать переменных состояния?

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

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно

  • 130 курсов, 2000+ часов теории
  • 1000 практических заданий в браузере
  • 360 000 студентов

Наши выпускники работают в компаниях:

Почему не стоит всегда использовать «useState»

Здравствуйте, я фронтенд-разработчик и хочу поделиться своим мнением о том, почему не стоит всегда использовать useState.

2.2K открытий

useState — это асинхронный хук, и он не меняет состояние сразу, он должен ждать повторного рендеринга компонента.

useRef — это синхронный хук, который немедленно обновляет состояние и сохраняет его значение на протяжении всего жизненного цикла компонента и не запускает повторный рендер компонента.

Почему я люблю useRef?

1 — useState

Посмотрите на пример ниже

Вы знаете, что произойдет?

useState является асинхронным хуком, он будет ждать завершения цикла компонента, повторного рендеринга, а затем обновит состояние. Таким образом, userToken (строка 20) будет пустой строкой.

Когда мне нужно сделать что-то сразу и это необходимо для потока моего кода, тогда я выбираю useRef. Почему? Потому, что он сохраняет значение на протяжении всего жизненного цикла компонента, но самое интересное, что он синхронный!

Давайте перепишем пример выше и заставим его работать!

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

useRef предназначен только для сохранения состояния и синхронного обновления, однако он не вызывает повторного рендеринга. Поэтому не стоит везде заменять useState на useRef.

3 — обычная переменная

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

Как работает useState

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

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

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

Как он сохраняет значение состояния при повторных рендерингах компонента? Все дело в замыкании.

Замыкания дают нам возможность создавать функции с «памятью», которая сохраняется, что означает, что при повторном выполнении функции у нее будет ссылка на предыдущее выполнение. Давайте объясню:

const playGame = () => < let counter = 0; const increment = () => < if(counter === 9)< console.log("Don't you have something better to do?") return >counter+=1 console.log(counter) > return increment; > const onClick = playGame(); onClick() onClick() onClick() onClick() onClick() onClick() onClick() onClick() onClick() onClick()

Попробуйте этот код у себя в консоли.
Догадались, что здесь произошло?
Именно, замыкание сохраняет «кэш» или «память» области видимости функции, к которой функция может получить доступ, даже если она выполняется снаружи.

Спасибо, что прочитали статью!

Почему не работает 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) =>

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

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