web-dev-qa-db-fra.com

Rétablir l'état initial avec React Hooks

Je travaille actuellement sur un formulaire d'inscription et voici un extrait de mon code:

const Signup = () => {
    const [username, setUsername] = useState('')
    const [email, setEmail] = useState('')
    const [password, setPassword] = useState('')
    const [passwordConfirmation, setPasswordConfirmation] = useState('')

    const clearState = () => {
        setUsername('')
        setEmail('')
        setPassword('')
        setPasswordConfirmation('')
    }

    const handleSubmit = signupUser => e => {
        e.preventDefault()
        signupUser().then(data => {
            console.log(data)
            clearState() // <-----------
        })
    }

    return <JSX />
}

export default Signup

Chaque élément d'état est utilisé pour une entrée contrôlée pour le formulaire.

Essentiellement, ce que je veux faire, c'est après que l'utilisateur s'est inscrit avec succès, je veux que l'état revienne à l'état initial avec les champs effacés.

Il est impératif de remettre manuellement chaque état dans des chaînes vides dans clearState Je me demandais s'il y avait une méthode ou une fonction fournie avec React qui réinitialise l'état à son état initial) Valeurs initiales?

35
avatarhzh

Malheureusement, il n'existe aucun moyen intégré de définir l'état à sa valeur initiale.

Votre code semble bon, mais si vous souhaitez réduire les fonctions nécessaires, vous pouvez placer l'intégralité de votre état de formulaire dans un seul objet variable d'état et réinitialiser à l'objet initial.

Exemple

const { useState } = React;

function signupUser() {
  return new Promise(resolve => {
    setTimeout(resolve, 1000);
  });
}

const initialState = {
  username: "",
  email: "",
  password: "",
  passwordConfirmation: ""
};

const Signup = () => {
  const [
    { username, email, password, passwordConfirmation },
    setState
  ] = useState(initialState);

  const clearState = () => {
    setState({ ...initialState });
  };

  const onChange = e => {
    const { name, value } = e.target;
    setState(prevState => ({ ...prevState, [name]: value }));
  };

  const handleSubmit = e => {
    e.preventDefault();
    signupUser().then(clearState);
  };

  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label>
          Username:
          <input value={username} name="username" onChange={onChange} />
        </label>
      </div>
      <div>
        <label>
          Email:
          <input value={email} name="email" onChange={onChange} />
        </label>
      </div>
      <div>
        <label>
          Password:
          <input
            value={password}
            name="password"
            type="password"
            onChange={onChange}
          />
        </label>
      </div>
      <div>
        <label>
          Confirm Password:
          <input
            value={passwordConfirmation}
            name="passwordConfirmation"
            type="password"
            onChange={onChange}
          />
        </label>
      </div>
      <button>Submit</button>
    </form>
  );
};

ReactDOM.render(<Signup />, document.getElementById("root"));
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="root"></div>
35
Tholle

Je pense que la réponse votée est toujours correcte, mais récemment React a publié le nouveau useReducer intégré qui, selon leurs propres mots, est

pratique pour réinitialiser l'état plus tard en réponse à une action

https://reactjs.org/docs/hooks-reference.html#usereducer

Il indique également qu'il est généralement préférable d'utiliser useReducer lorsque vous avez une logique d'état complexe qui implique plusieurs sous-valeurs ou lorsque l'état suivant dépend du précédent.

En utilisant le même échantillon sur la réponse votée, vous pouvez utiliser useReducer comme ceci:

Javascript

import React, { useReducer } from "react";

const initialState = {
    username: "",
    email: "",
    password: "",
    passwordConfirmation: "",
};

const reducer = (state, action) => {
    if (action.type === "reset") {
        return initialState;
    }

    const result = { ...state };
    result[action.type] = action.value;
    return result;
};

const Signup = () => {
    const [state, dispatch] = useReducer(reducer, initialState);
    const { username, email, password, passwordConfirmation } = state;

    const handleSubmit = e => {
        e.preventDefault();

        /* fetch api */

        /* clear state */
        dispatch({ type: "reset" });
    };

    const onChange = e => {
        const { name, value } = e.target;
        dispatch({ type: name, value });
    };

    return (
        <form onSubmit={handleSubmit}>
            <div>
                <label>
                    Username:
                    <input value={username} name="username" onChange={onChange} />
                </label>
            </div>
            <div>
                <label>
                    Email:
                    <input value={email} name="email" onChange={onChange} />
                </label>
            </div>
            <div>
                <label>
                    Password:
                    <input
                        value={password}
                        name="password"
                        type="password"
                        onChange={onChange}
                    />
                </label>
            </div>
            <div>
                <label>
                    Confirm Password:
                    <input
                        value={passwordConfirmation}
                        name="passwordConfirmation"
                        type="password"
                        onChange={onChange}
                    />
                </label>
            </div>
            <button>Submit</button>
        </form>
    );
};

export default Signup;

Manuscrit

import React, { FC, Reducer, useReducer } from "react";

interface IState {
    email: string;
    password: string;
    passwordConfirmation: string;
    username: string;
}

interface IAction {
    type: string;
    value?: string;
}

const initialState: IState = {
    email: "",
    password: "",
    passwordConfirmation: "",
    username: "",
};

const reducer = (state: IState, action: IAction) => {
    if (action.type === "reset") {
        return initialState;
    }

    const result: IState = { ...state };
    result[action.type] = action.value;
    return result;
};

export const Signup: FC = props => {
    const [state, dispatch] = useReducer<Reducer<IState, IAction>, IState>(reducer, initialState, () => initialState);
    const { username, email, password, passwordConfirmation } = state;

    const handleSubmit = (e: React.FormEvent) => {
        e.preventDefault();

        /* fetch api */

        /* clear state */
        dispatch({ type: "reset" });
    };

    const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
        const { name, value } = e.target;
        dispatch({ type: name, value });
    };

    return (
        <form onSubmit={handleSubmit}>
            <div>
                <label>
                    Username:
                    <input value={username} name="username" onChange={onChange} />
                </label>
            </div>
            <div>
                <label>
                    Email:
                    <input value={email} name="email" onChange={onChange} />
                </label>
            </div>
            <div>
                <label>
                    Password:
                    <input
                        value={password}
                        name="password"
                        type="password"
                        onChange={onChange}
                    />
                </label>
            </div>
            <div>
                <label>
                    Confirm Password:
                    <input
                        value={passwordConfirmation}
                        name="passwordConfirmation"
                        type="password"
                        onChange={onChange}
                    />
                </label>
            </div>
            <button>Submit</button>
        </form>
    );
};

Notez que j'ai créé cette fonction reducer const pour qu'elle soit aussi générique que possible, mais vous pouvez la changer complètement et tester différents types d'actions (autres que simplement indiquer les noms de propriétés) et effectuer des calculs complexes avant de renvoyer l'état modifié. Il y a quelques exemples dans le lien fourni ci-dessus.

11
Guilherme

Comme je le sais (en lisant les documents React) - il n'y a aucun moyen de le faire pour l'instant.

3
java-man-script

Vous pouvez utiliser une variable d'état comme décrit dans le FAQ ici: https://reactjs.org/docs/hooks-faq.html#should-i-use-one- ou-plusieurs-états-variables

Cela dépend bien sûr de votre cas d'utilisation.

La recomposition du composant à partir du conteneur parent le réinitialisera également automatiquement, bien sûr.

2
jontro

Parallèlement aux autres réponses, je recommanderais de prendre une bibliothèque d'aide comme celle-ci , ou de faire votre propre abstraction au-dessus des crochets, si c'est quelque chose que vous ferez souvent.

useState et amis ne sont en fait que des primitives de bas niveau pour vous, l'utilisateur, pour créer des crochets plus utiles par-dessus. J'ai des projets où les appels bruts useState sont en fait assez rares.

2
kingdaro

Vous auriez pu utiliser useRef dans les crochets quelque chose comme ça

 const myForm = useRef(null)

 const submit = () => {

   myForm.current.reset(); // will reset the entire form :)

   }

  <form ref={myForm} onSubmit={submit}>

   <input type="text" name="name" placeholder="John Doe">

     <input type="email" name="name" placeholder="[email protected]">

     <button type="submit">Submit</button>

 </form>
1
Usman I

J'ai totalement accepté la réponse de @ Tholle.

Si vous devez exécuter certaines fonctions après la suppression de l'état

const clearState = () => {
  setState({...initialState});
  return {
    foo,
    bar,
    // ...
  };
};

// when component is unmounted

() => clearState().foo();
() => clearState().bar();
0
Lanon

C'est ainsi que vous pouvez réinitialiser valeurs d'entrée (à partir de l'objet) dans hooks après la soumission du formulaire.

Vous pouvez définir plusieurs valeurs d'entrée dans le même useState comme firstName, lastName, etc ...

const [state, setState] = React.useState({ firstName: "", lastName: "" });

Exemple de code.

export default function App() {
  const [state, setState] = React.useState({ firstName: "", lastName: "" });
  const handleSubmit = e => {
    e.preventDefault();
    setState({firstName:'',lastName:''})
  };
  const handleChange = e => {
    const { name, value } = e.target;
    setState({ ...state, [name]: value });
  };
  console.log(state)
  return (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        name="firstName"
        placeholder="Enter first name"
        value={state.firstName}
        onChange={handleChange}
      />
      <input
        type="text"
        name="lastName"
        placeholder="Enter last name"
        value={state.lastName}
        onChange={handleChange}
      />
      <input type="submit" value="Submit" />
    </form>
  );
}

Si vous souhaitez que plusieurs entrées soient définies dans l'objet au lieu de déclarer séparément.

0
Vahid Akhtar

J'ai eu un cas d'utilisation similaire. Complètement indépendant d'un mécanisme de connexion, d'inscription, mais je l'ai modifié pour qu'il soit lié à votre cas d'utilisation.

À mon avis, un moyen facile de résoudre ce problème est d'utiliser un composant parent.

const initUser = {
  name: '',
  email: '',
  password: '',
  passwordConfirmation: ''      
}

const LoginManager = () => {
  const [user, setUser] = useState(initUser)

  return <Signup user={user} resetUser={setUser} />
}

const Signup = ({user, resetUser}) => {
    const [username, setUsername] = useState(user.name)
    const [email, setEmail] = useState(user.email)
    const [password, setPassword] = useState(user.password)
    const [passwordConfirmation, setPasswordConfirmation] = useState(user.passwordConfirmation)


    const handleSubmit = signupUser => e => {
        e.preventDefault()
        signupUser().then(data => {
            console.log(data)
            resetUser(initUser) // <-----------
        })
    }

    return <JSX />
}

export default Signup
0
Matthis Kohli