Странное поведение React setState с изменением переменной let

Код ниже отобразит <h1> и два <button>.

В моем ожидании, changeString1<button> изменит letString на 1 и, наконец, изменит <h1> текст на 1, а changeString2<button>

  1. изменить <h1> текст на 3если я сначала нажму changeString2
  2. изменить <h1> текст на 1если я сначала нажму changeString1

Но по факту

  1. Если я сначала нажму changeString1однажды, затем нажму changeString2, <h1> текст будет 3 ! Но почему?
  2. Что еще, если я сначала нажму changeString1дважды, затем нажму changeString2, <h1> текст будет 1 ! Но почему?

Кажется, что оба факта противоречат друг другу...

Вы можете проверить это с помощью https://codesandbox.io/s/wy4l1y4o8

import React, { useState } from "react";
import ReactDOM from "react-dom";

function App() {
  let letString = "3";
  const [statString, setStatString] = useState("2");

  function changeString1() {
    letString = "1";
    setStatString(letString);
  }

  function changeString2() {
    console.info(letString);
    setStatString(letString);
  }

  return (
    <div>
      <h1>{statString}</h1>
      <button onClick = {changeString1}>changeString1</button>
      <button onClick = {changeString2}>changeString2</button>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Я думаю, вы нашли артефакт. Совет типа «не использовать локальную переменную» решит ваш случай, но не отвечает на вопрос, почему он остается «1» после двух щелчков мыши. Теоретически он не должен зависать на "1".

rishat 16.03.2019 00:43
Поведение ключевого слова "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) для оценки ваших знаний,...
2
1
454
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Когда вы нажимаете на изменитьСтрока2, значение локальной переменной letString равно 3.

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

но почему на самом деле 2, я нажимаю на changeString2 результаты, чтобы текст <h1> был 1?

Sora Shiro 15.03.2019 22:37

Если вы поместите console.info('rendering', letString) непосредственно перед возвратом функции, вы увидите, что значение letString всегда равно '3' при рендеринге. Неважно, что вы меняете его внутри локальной функции changeString1, когда компонент собирается отрендериться, letString снова инициализируется значением 3.

jgoday 15.03.2019 22:49

Вы должны отслеживать нажатие на changeString1 в отдельной переменной:

const {useState} = React

function App() {
  const [statString, setStatString] = useState("2");
  const [clicked, setClicked] = useState(false)

  function changeString1() {
    setClicked(true)
    setStatString("1");
  }

  function changeString2() {
    setStatString(clicked ? "1" : "3");
  }

  return (
    <div>
      <h1>{statString}</h1>
      <button onClick = {changeString1}>changeString1</button>
      <button onClick = {changeString2}>changeString2</button>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script crossorigin src = "https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script crossorigin src = "https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
<div id = "root" />

Причина, по которой ваш код не работал должным образом, заключается в том, что каждый вызов App создает новый экземпляр переменной letState, которая связана с функцией changeString2, когда она равна определенный. React оптимизирует вызовы, которые не изменяют состояние, избегая ненужного повторного рендеринга. Поэтому, когда вы нажимаете второй раз, вы не вызываете замены функций обратного вызова. Поэтому, когда вы нажимаете на changeState2, это та же функция, что и в «предыдущем» рендере.

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

Пожалуйста, посмотрите на поток, который имеет место: -

1st click on changeString1

state changes

component re renders

letString gets re-initialized to 3 because of let letString = "3"

value of letString = 3;
value of statString = 1 (state);

2nd click on changeString1

value of letString gets set to 1 in the function call;

But value of statString(state) is already 1 so no state changes and component never re-renders and letString is not re-initialized

After 2nd click values are:-

letString = 1;
statString = 1(state);

Now, when you click on changeString2 value of letString is 1 and statString is also 1 so state doesn't changes and nothing happens and you just see 1.

Это имеет смысл. Я попытался добавить третью кнопку с именем changeString3, которая вызывает выполнение функции setStatString("4");. После того, как я дважды щелкну changeString1 и щелкну один раз changeString3, щелкните один раз changeString2, наконец, результат <h1> text будет 3 снова. Таким образом, ключевым моментом является то, что если компонент не нуждается в повторном рендеринге, его локальные переменные не будут повторно инициализированы?

Sora Shiro 16.03.2019 03:57

Да, ты понял. Когда компонент не визуализируется повторно, letString не запускается повторно и остается без изменений. Но не в случае с государством. Состояние инициализируется только один раз при монтировании компонента, а не при дальнейшем повторном рендеринге.

cEeNiKc 16.03.2019 04:13

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