web-dev-qa-db-ja.com

Reactフックで初期状態にリセット

私は現在サインアップフォームに取り組んでおり、以下は私のコードのスニペットです。

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

状態の各部分は、フォームの制御された入力に使用されます。

基本的に、ユーザーが正常にサインアップした後、状態を初期状態に戻し、フィールドをクリアします。

状態の各部分を空の文字列に手動で戻す必要がありますin clearState Reactに付属するメソッドまたは関数があり、状態を元に戻すかどうか疑問に思っていました初期値?

35
avatarhzh

残念ながら、状態を初期値に設定する組み込みの方法はありません。

コードは適切に見えますが、必要な関数を減らしたい場合は、フォームの状態全体を単一の状態変数オブジェクトに入れ、初期オブジェクトにリセットできます。

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

投票された答えはまだ正しいと思いますが、最近Reactが新しい組み込みuseReducerをリリースしました。

後でアクションに応答して状態をリセットするのに便利です

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

また、複数のサブ値を含む複雑な状態ロジックがある場合、または次の状態が前の状態に依存している場合は、通常はuseReducerが望ましいと述べています。

投票した回答で同じサンプルを使用すると、次のようにuseReducerを使用できます。

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;

TypeScript

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>
    );
};

このreducer関数constを可能な限り汎用的に作成したことに注意してください。ただし、これを完全に変更し、さまざまなアクションタイプ(単にプロパティ名をステートする以外)をテストして、変更されたステートを返す前に複雑な計算を実行できます。上記のリンクにいくつかの例があります。

11
Guilherme

私が知っているように(反応ドキュメントを読んで)-まだそうする方法はありません。

3
java-man-script

FAQ here: https://reactjs.org/docs/hooks-faq.html#should-i-use-one- or-many-state-variables

もちろん、それはあなたのユースケースに依存します。

もちろん、親コンテナからコンポーネントのキーを変更しても、コンポーネントは自動的にリセットされます。

2
jontro

他の回答と一緒に、ヘルパーライブラリを入手することをお勧めします これのように 、またはこれが頻繁に実行するものである場合は、フックの上に独自の抽象化を作成します。

useStateと友達は、その上にさらに便利なフックを構築するための、ユーザーである低レベルのプリミティブです。生のuseState呼び出しが実際にかなり珍しいプロジェクトがあります。

2
kingdaro

あなたはこのようなフックでuseRefを使うことができたでしょう

 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

@Tholleの答えに完全に同意しました。

状態がクリアされた後にいくつかの機能を実行する必要がある場合

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

// when component is unmounted

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

これは、入力値(オブジェクトから)をリセットする方法ですフックフォーム送信後。

同じuseStateに複数の入力値を定義できますfirstNamelastNameetc...

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

サンプルコード。

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>
  );
}

複数の入力を個別に宣言するのではなく、オブジェクトで定義する場合。

0
Vahid Akhtar

同様のユースケースがありました。ログイン、サインアップメカニズムとは完全に無関係ですが、ユースケースに関連するように変更しました。

これを解決する簡単な方法は、私の考えでは親コンポーネントを使用することです。

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