React useState Hook setter 对数组变量没有结果
React useState Hook setter has no result with array variable
我正在尝试将在 udemy 课程中看到的示例从基于 class 的有状态组件改编为基于函数的组件,使用 React 16.7.0-alpha.2 的 useState 挂钩
虽然原始数据类型的 setter 函数工作正常(例如 setUsername),但为数组变量调用 setter 没有 effect/result。至少它不会将状态变量重置回空数组。
另一方面,使用 concat 方法从 state 设置数组的新副本按预期工作。
我对 React hooks 还是个新手,想知道我错过了什么吗?
import React, {useState} from 'react';
import { Grid, Form, Segment, Button, Header, Message, Icon } from 'semantic-ui-react';
import { Link } from 'react-router-dom';
import { registerUser } from './authFunctions';
import { isRegisterFormEmpty } from './validatorFunctions';
const Register = () => {
//defining state properties and setters:
const [username, setUsername] = useState('');
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [passwordConfirmation, setPasswordConfirmation] = useState('');
const [registerErrors, setRegisterErrors] = useState([]);
//defining handlers:
const onUsernameChange = e => setUsername(e.target.value);
const onEmailChange = e => setEmail(e.target.value);
const onPasswordChange = e => setPassword(e.target.value);
const onPasswordConfirmationChange = e => setPasswordConfirmation(e.target.value);
const onFormSubmit = e => {
e.preventDefault(); //prevent a page reload
//set registerErrors to empty array in case that the user clicks on submit again
setRegisterErrors([]); // DOES NOT WORK
setUsername('JDoe'); //works as expected
if( isRegisterFormEmpty(username, email, password, passwordConfirmation) ) {
let error = {message: 'Please fill in all fields'};
setRegisterErrors( registerErrors.concat(error) ); //THIS WORKS FINE, THOUGH...
} else {
//registerUser(username, email, password, passwordConfirmation);
}//if
}//onFormSubmit
const showErrors = () => registerErrors.map( (error, idx) => <p key={idx}>{error.message}</p> );
return (
<Grid textAlign='center' verticalAlign='middle' className='app'>
<Grid.Column style={{ maxWidth: 450 }}>
<Header as='h2' icon color='teal' textAlign='center'>
<Icon name='puzzle piece' color='teal' />
Register to DevChat
</Header>
<Form size='large' onSubmit={onFormSubmit}>
<Segment stacked>
<Form.Input
fluid
type='text'
icon='user'
iconPosition='left'
placeholder='Username'
onChange={onUsernameChange}
value={username}
/>
<Form.Input
fluid
type='email'
icon='mail'
iconPosition='left'
placeholder='Email'
onChange={onEmailChange}
value={email}
/>
<Form.Input
fluid
type='password'
icon='lock'
iconPosition='left'
placeholder='Password'
onChange={onPasswordChange}
value={password}
/>
<Form.Input
fluid
type='password'
icon='lock'
iconPosition='left'
placeholder='Password Confirmation'
onChange={onPasswordConfirmationChange}
value={passwordConfirmation}
/>
<Button
color='teal'
fluid
size='large'
content='Submit'
/>
</Segment>
</Form>
{
registerErrors.length > 0 &&
<Message error>
<h3>Please note</h3>
{showErrors()}
</Message>
}
<Message>
Already a user? <Link to='/login'>Login</Link>
</Message>
</Grid.Column>
</Grid>
)
}
export default Register;
这是常见的 useState
陷阱。
setRegisterErrors([])
有效,它不可能因为被调用而无效。它触发同步组件更新。由于 onFormSubmit
在那之后没有退出,因此在那之后调用 setRegisterErrors(registerErrors.concat(error))
,其中 registerErrors
是在 onFormSubmit
之外定义的先前状态。
onFormSubmit
导致 2 次寄存器状态更新,其中第二次更新(连接的原始数组)覆盖第一次更新(空数组)。
解决此问题的方法与 setState
相同,即使用提供要更新的当前状态的状态更新器函数:
setRegisterErrors(registerErrors => [...registerErrors, error]);
或者,可以合并寄存器状态更新:
e.preventDefault();
const registerErrors = [];
setUsername('JDoe');
if( isRegisterFormEmpty(username, email, password, passwordConfirmation) ) {
registerErrors.push({message: 'Please fill in all fields'});
} else {
...
}
setRegisterErrors(registerErrors);
我正在尝试将在 udemy 课程中看到的示例从基于 class 的有状态组件改编为基于函数的组件,使用 React 16.7.0-alpha.2 的 useState 挂钩
虽然原始数据类型的 setter 函数工作正常(例如 setUsername),但为数组变量调用 setter 没有 effect/result。至少它不会将状态变量重置回空数组。
另一方面,使用 concat 方法从 state 设置数组的新副本按预期工作。
我对 React hooks 还是个新手,想知道我错过了什么吗?
import React, {useState} from 'react';
import { Grid, Form, Segment, Button, Header, Message, Icon } from 'semantic-ui-react';
import { Link } from 'react-router-dom';
import { registerUser } from './authFunctions';
import { isRegisterFormEmpty } from './validatorFunctions';
const Register = () => {
//defining state properties and setters:
const [username, setUsername] = useState('');
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [passwordConfirmation, setPasswordConfirmation] = useState('');
const [registerErrors, setRegisterErrors] = useState([]);
//defining handlers:
const onUsernameChange = e => setUsername(e.target.value);
const onEmailChange = e => setEmail(e.target.value);
const onPasswordChange = e => setPassword(e.target.value);
const onPasswordConfirmationChange = e => setPasswordConfirmation(e.target.value);
const onFormSubmit = e => {
e.preventDefault(); //prevent a page reload
//set registerErrors to empty array in case that the user clicks on submit again
setRegisterErrors([]); // DOES NOT WORK
setUsername('JDoe'); //works as expected
if( isRegisterFormEmpty(username, email, password, passwordConfirmation) ) {
let error = {message: 'Please fill in all fields'};
setRegisterErrors( registerErrors.concat(error) ); //THIS WORKS FINE, THOUGH...
} else {
//registerUser(username, email, password, passwordConfirmation);
}//if
}//onFormSubmit
const showErrors = () => registerErrors.map( (error, idx) => <p key={idx}>{error.message}</p> );
return (
<Grid textAlign='center' verticalAlign='middle' className='app'>
<Grid.Column style={{ maxWidth: 450 }}>
<Header as='h2' icon color='teal' textAlign='center'>
<Icon name='puzzle piece' color='teal' />
Register to DevChat
</Header>
<Form size='large' onSubmit={onFormSubmit}>
<Segment stacked>
<Form.Input
fluid
type='text'
icon='user'
iconPosition='left'
placeholder='Username'
onChange={onUsernameChange}
value={username}
/>
<Form.Input
fluid
type='email'
icon='mail'
iconPosition='left'
placeholder='Email'
onChange={onEmailChange}
value={email}
/>
<Form.Input
fluid
type='password'
icon='lock'
iconPosition='left'
placeholder='Password'
onChange={onPasswordChange}
value={password}
/>
<Form.Input
fluid
type='password'
icon='lock'
iconPosition='left'
placeholder='Password Confirmation'
onChange={onPasswordConfirmationChange}
value={passwordConfirmation}
/>
<Button
color='teal'
fluid
size='large'
content='Submit'
/>
</Segment>
</Form>
{
registerErrors.length > 0 &&
<Message error>
<h3>Please note</h3>
{showErrors()}
</Message>
}
<Message>
Already a user? <Link to='/login'>Login</Link>
</Message>
</Grid.Column>
</Grid>
)
}
export default Register;
这是常见的 useState
陷阱。
setRegisterErrors([])
有效,它不可能因为被调用而无效。它触发同步组件更新。由于 onFormSubmit
在那之后没有退出,因此在那之后调用 setRegisterErrors(registerErrors.concat(error))
,其中 registerErrors
是在 onFormSubmit
之外定义的先前状态。
onFormSubmit
导致 2 次寄存器状态更新,其中第二次更新(连接的原始数组)覆盖第一次更新(空数组)。
解决此问题的方法与 setState
相同,即使用提供要更新的当前状态的状态更新器函数:
setRegisterErrors(registerErrors => [...registerErrors, error]);
或者,可以合并寄存器状态更新:
e.preventDefault();
const registerErrors = [];
setUsername('JDoe');
if( isRegisterFormEmpty(username, email, password, passwordConfirmation) ) {
registerErrors.push({message: 'Please fill in all fields'});
} else {
...
}
setRegisterErrors(registerErrors);