React useState Hook setter не имеет результата с переменной массива - PullRequest
0 голосов
/ 12 января 2019

Я пытаюсь адаптировать пример, видимый на курсе udemy из основанного на классе компонента с компонентом на основе функций, используя хук useState с React 16.7.0-alpha.2

Хотя функции-установщики для примитивных типов данных работают нормально (например, setUsername), вызов метода-установщика для переменной массива не имеет никакого эффекта / результата. По крайней мере, он не сбрасывает переменную состояния обратно в пустой массив.

С другой стороны, установка новой копии массива из состояния с помощью метода concat работает как положено.

Я все еще новичок в ловушках React и интересно, что я пропустил?

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;

1 Ответ

0 голосов
/ 13 января 2019

Это обычная 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);
...