# Part 76: Enhancing User Authentication with a Custom React Hook

<figure><img src="https://159896965-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F3LclXKUpANLoSt8DPdYV%2Fuploads%2FJK8G3Yjm1qHwjGSqwUcV%2F1675674296261.jpeg?alt=media&#x26;token=989182c4-9098-4bba-8dd9-52aeb4b0f941" alt=""><figcaption><p>[Pages] React Query</p></figcaption></figure>

In modern web development, creating a seamless user experience often involves efficiently managing API requests and state updates. When building a login system, we can simplify our codebase by encapsulating common functionality into reusable components or hooks. In this blog post, we'll explore how to create a custom React hook to handle the login process and streamline our code.

### The Objective: Creating a Custom Hook for Sign-In

Our goal is to refactor the login logic from the `SignInPage` component into a custom hook called `useSignIn`. This will encapsulate the login process, including the API call and cache update, making our `SignInPage` component cleaner and more focused.

#### Problem with Direct Code Movement

Initially, the `SignInPage` component uses React Query's `useMutation` to handle login requests, updating the cache with `queryClient.setQueryData`. However, moving this logic directly into a separate file presents a challenge: state variables like `email` and `password` are not accessible outside the component.

#### Solution: Passing Parameters to the Mutation Function

React Query provides a mechanism to pass parameters to the mutation function, allowing us to send `email` and `password` as arguments. This makes it possible to move the login logic into a custom hook.

#### Creating the Custom Hook: `useSignIn`

Let's create the `useSignIn` hook that encapsulates the login logic, handles API interaction, and updates the cache.

```javascript
// File: hooks/user.js

import { useMutation, useQueryClient } from 'react-query';
import { fetchJson } from '../lib/api';

export function useSignIn() {
  const queryClient = useQueryClient();
  const mutation = useMutation(({ email, password }) => fetchJson('/api/login', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ email, password }),
  }));
  
  return {
    signIn: async (email, password) => {
      try {
        const user = await mutation.mutateAsync({ email, password });
        queryClient.setQueryData('user', user);
        return true;
      } catch (err) {
        return false;
      }
    },
    signInError: mutation.isError,
    signInLoading: mutation.isLoading,
  };
}
```

#### Key Elements of `useSignIn`

1. **Mutation Function**: The hook uses `useMutation` to define the API request logic, receiving `email` and `password` as arguments.
2. **Cache Update**: After a successful login, `setQueryData` updates the cache with the new user data.
3. **Return Object**: The hook returns an object containing:
   * `signIn`: An asynchronous function to execute the login.
   * `signInError`: A boolean indicating if there was an error.
   * `signInLoading`: A boolean indicating if the request is in progress.

#### Refactoring `SignInPage`

Now, let's refactor `SignInPage` to use `useSignIn`.

```javascript
// File: pages/sign-in.js

import { useRouter } from 'next/router';
import { useState } from 'react';
import Button from '../components/Button';
import Field from '../components/Field';
import Input from '../components/Input';
import { useSignIn } from '../hooks/user';

function SignInPage() {
  const router = useRouter();
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const { signIn, signInError, signInLoading } = useSignIn();

  const handleSubmit = async (event) => {
    event.preventDefault();
    const valid = await signIn(email, password);
    if (valid) {
      router.push('/');
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <Field label="Email">
        <Input
          type="email"
          value={email}
          onChange={(event) => setEmail(event.target.value)}
        />
      </Field>
      <Field label="Password">
        <Input
          type="password"
          value={password}
          onChange={(event) => setPassword(event.target.value)}
        />
      </Field>
      {signInError && (
        <p className="text-red-700">Invalid credentials</p>
      )}
      {signInLoading ? (
        <p>Loading...</p>
      ) : (
        <Button type="submit">Sign In</Button>
      )}
    </form>
  );
}

export default SignInPage;
```

#### Benefits of Using `useSignIn`

1. **Code Reusability**: The login logic is encapsulated, making it reusable across different components.
2. **Cleaner Components**: `SignInPage` is now more focused on rendering, with minimal logic.
3. **Customizable Behavior**: The hook can be tailored to return specific values, improving code readability and maintainability.

### Conclusion

By extracting the login logic into a custom hook, we've not only cleaned up our component code but also made our logic more reusable and maintainable. This approach is a great way to manage complex stateful logic in React applications, providing a modular and efficient way to handle API interactions.
