React useState() не обновляет значение переменной, если вызывается сразу после установки значения.
Я читал об useEffect(), но не знаю, как это будет полезно для этого конкретного сценария.
Полный код (пожалуйста, откройте вкладку консоли, чтобы увидеть статус переменной)
// hook
const [ error, setError ] = useState<boolean>();
const handleSubmit = (e: any): void => {
e.preventDefault();
if (email.length < 4) {
setError(true);
}
if (password.length < 5) {
setError(true);
}
console.info(error); // <== still false even after setting it to true
if (!error) {
console.info("validation passed, creating token");
setToken();
} else {
console.info("errors");
}
};
Привет, Tronpora, только что написал тебе ответ, дай мне знать, если у тебя возникнут вопросы.






Как и setState, useState является асинхронным и имеет тенденцию объединять обновления в пакет, пытаясь повысить производительность. Вы на правильном пути с useEffect, который позволит вам эффективно выполнять обратный вызов после обновления состояния.
Пример из документы:
import React, { useState, useEffect } from 'react';
function Example() {
const [count, setCount] = useState(0);
// Similar to componentDidMount and componentDidUpdate:
useEffect(() => {
// Update the document title using the browser API
document.title = `You clicked ${count} times`;
});
return (
<div>
<p>You clicked {count} times</p>
<button onClick = {() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
Хотя также рекомендуется, чтобы, если вам нужно обновленное значение, как только было запрошено обновление состояния, вам, вероятно, лучше использовать только переменную в компоненте.
Подробнее об использовании состояния синхронно
И если вы знакомы с редюсерами Redux, вы можете использовать useReducer в качестве другой альтернативы. Из документы:
useReducer is usually preferable to useState when you have complex state logic that involves multiple sub-values or when the next state depends on the previous one. useReducer also lets you optimize performance for components that trigger deep updates because you can pass dispatch down instead of callbacks.
Как использовать useEffect? и не является ли useReducer слишком сложным для этого простого сценария?
Я не совсем уверен, чего вы пытаетесь достичь, но, как я уже сказал, вам может быть лучше просто переменная вне состояния. Если я правильно понимаю, вы пытаетесь прочитать состояние сразу после его установки. Поэтому переместите код, который считывает состояние, в стрелочную функцию, переданную useEffect. Затем он не будет вызываться, пока состояние не завершит обновление.
чего я пытаюсь добиться, так это после отправки формы я делаю некоторую проверку, и если проверка не имеет ошибок, я вызываю функцию setToken(), в противном случае я просто регистрирую сообщение. Как вы упомянули, решение будет заключаться в использовании useEffect, но я не совсем уверен, как это реализовать в этом сценарии. Я пробовал следующее: useEffect(()=> {}, [error]); но не работал. Я обновил вопрос.
Предположим, что у пользователя нет действительных учетных данных. Проблема здесь:
if (email.length < 4) { // <== this gets executed
setError(true);
}
if (password.length < 5) { // <== this gets executed
setError(true);
}
console.info(error); // <== still false even after setting it to true
if (!error) { // <== this check runs before setError(true) is complete. error is still false.
console.info("validation passed, creating token");
setToken();
} else {
console.info("errors");
}
Вы используете несколько проверок if, которые выполняются независимо друг от друга, а не одну. Ваш код выполняет все проверки if. В одной проверке вы вызываете setError(true) при выполнении одного из условий, но setError() асинхронно. Действие не завершается до вызова следующей проверки if, поэтому создается впечатление, что ваше значение никогда не сохранялось.
Вместо этого вы можете сделать это более аккуратно, используя комбинацию if-else и useEffect: https://codesandbox.io/s/dazzling-pascal-78gqp
import * as React from "react";
const Login: React.FC = (props: any) => {
const [email, setEmail] = React.useState("");
const [password, setPassword] = React.useState("");
const [error, setError] = React.useState(null);
const handleEmailChange = (e: any): void => {
const { value } = e.target;
setEmail(value);
};
const handlePasswordChange = (e: any): void => {
const { value } = e.target;
setPassword(value);
};
const handleSubmit = (e: any): void => {
e.preventDefault();
if (email.length < 4 || password.length < 5) {
setError(true);
} else {
setError(false);
}
};
const setToken = () => {
//token logic goes here
console.info("setting token");
};
React.useEffect(() => {
if (error === false) {
setToken();
}
}, [error]); // <== will run when error value is changed.
return (
<div>
<form onSubmit = {handleSubmit}>
<input
type = "text"
placeholder = "[email protected]"
onChange = {handleEmailChange}
/>
<br />
<input
type = "password"
placeholder = "password"
onChange = {handlePasswordChange}
/>
<br />
<input type = "submit" value = "submit" />
</form>
{error ? <h1>error true</h1> : <h1>error false</h1>}
</div>
);
};
export default Login;
Добро пожаловать @Tronpora! Я рад, что это помогло вам :)
Добавьте некоторый код к своему вопросу и объясните, чего вы пытаетесь достичь, сказав, что «не обновляет значение переменной, вызываемой сразу после установки значения», недостаточно. См. Как задать хороший вопрос