3

In RecoilJS docs, there is an example how to handle asynchronous data queries, but it's only about get data.

Let say I have a simple state:

const accountState = atom({
  key: "accountState",
  default: {
    id: "",
    name: "",
  }
});

And a component which is a register form:

const RegisterForm = () => {
  return (
    <form>
      <input type="text" name="username" />
      <button type="submit">Register</button>
    </form>
  )
}

The posted data is in FormData. After successfully created new account, the server will send a response that contains id and name of the account.

{
  "id": "abcdef123456",
  "name": "example"
}

This response data will be set as a new state of accountState.

How can I handle the process in RecoilJS?

Trí Phan
  • 1,123
  • 2
  • 15
  • 33

1 Answers1

2

You can just handle with http request and set the response to the state.

const RegisterForm = () => {
  const [account, setAccount] = useRecoilState(accountState);

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

    const response = await fetch(url, {
      method: 'POST',
      body: data,
    });

    const responseJson = await response.json();
    setAccount(responseJson);
  };

  return (
    <form onSubmit={handleSubmit}>
      <input type="text" name="username" />
      <button type="submit">Register</button>
    </form>
  );
}

Edit

To have a reusable approach, I will suggest to build custom hooks for frequent usage

const useRegister = () => {
  const setAccount = useSetRecoilState(accountState);

  const register = useCallback(async (username)=> {
    const response = await fetch(url, {
      method: 'POST',
      body: { username },
    });

    const responseJson = await response.json();
    setAccount(responseJson);
  }, [setAccount]);

  return register;

}

const RegisterForm = () => {
  const register = useRegister();

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

    await register(username);
  };

  return (
    <form onSubmit={handleSubmit}>
      <input type="text" name="username" />
      <button type="submit">Register</button>
    </form>
  );
}
Ewe Tek Min
  • 855
  • 10
  • 19
  • 3
    Yes, this is the basic approach. But when the project is getting larger and more complex, handling api call inside the component is not a good idea. I'm looking for other approaches that handle the async actions outside the component, like `redux-thunk` and `redux-saga` in `redux`. – Trí Phan Jul 11 '20 at 06:42
  • 2
    As far as I know, I don't aware of recoil provide any utils like saga to perform http request. If you want to reuse the API call in multiple places, I guess the best way is to create a custom hooks for each actions, that will be equivalent for `redux-thunk`. Please look at my edited answer, thanks – Ewe Tek Min Jul 11 '20 at 09:21
  • Is this answer still valid? I can't seem to find good documentation for the use case... – olefrank Dec 19 '22 at 14:00