Как создать пользовательский хук для публикации в API и сохранения результата?

#reactjs #typescript #react-redux #react-hooks

Вопрос:

У меня есть форма входа в систему, которая использует useState hook для хранения состояния входных данных (имя пользователя и пароль), поэтому я могу передать эти данные функции, используя createAsyncThunk эту запись в API, и сохранить ее результат.

В настоящее время вот что у меня есть:

Войдите в систему.tsx

 import React, { useState } from 'react';
import {
  Avatar,
  Button,
  Checkbox,
  Container,
  CssBaseline,
  FormControlLabel,
  Grid,
  Link,
  TextField,
  Typography,
} from '@material-ui/core';
import LockOutlinedIcon from '@material-ui/icons/LockOutlined';
import { makeStyles } from '@material-ui/core/styles';
import { useAuth } from '../hooks';
import { useHistory } from 'react-router';
import { authManager } from '../authManager';

const useStyles = makeStyles((theme) => ({
  //...
}));

const Login: React.FC = () => {
  const classes = useStyles();
  const { push } = useHistory();
  const [username, setUsername] = useState('');
  const [password, setPassword] = useState('');

  const handleUsername: React.ChangeEventHandler<HTMLInputElement> = (e) =>
    setUsername(e.target.value);
  const handlePassword: React.ChangeEventHandler<HTMLInputElement> = (e) =>
    setPassword(e.target.value);

  const SignIn = async () => {
    await useAuth(username, password);
  };

  return (
    <Container component="main" maxWidth="xs">
      <CssBaseline />
      <div className={classes.paper}>
        <Avatar className={classes.avatar}>
          <LockOutlinedIcon />
        </Avatar>
        <Typography component="h1" variant="h5">
          Sign in
        </Typography>
        <form className={classes.form} noValidate>
          <TextField
            variant="outlined"
            margin="normal"
            required
            fullWidth
            id="email"
            label="E-mail"
            name="email"
            autoComplete="email"
            value={username}
            onChange={handleUsername}
            autoFocus
          />
          <TextField
            variant="outlined"
            margin="normal"
            required
            fullWidth
            name="password"
            label="Senha"
            type="password"
            id="password"
            autoComplete="current-password"
            value={password}
            onChange={handlePassword}
          />
          <Button
            fullWidth
            variant="contained"
            color="primary"
            className={classes.submit}
            onClick={SignIn}
          >
            Sign In
          </Button>
        </form>
      </div>
    </Container>
  );
};

export default Login;
 

useAuth.ts (пользовательский крючок)

 import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { authOperations } from 'src/features/auth/redux/';
import { getAuth } from 'src/features/auth/redux/authSelector';

export default (username: string, password: string) => {
  const dispatch = useDispatch();
  const auth = useSelector(getAuth);

  useEffect(() => {
    dispatch(
      authOperations.getAccessToken({
        username,
        password,
      })
    );
  }, [dispatch, username, password]);

  return {
    auth,
  };
};
 

Это не работает, на самом деле я получаю Invalid hook call. Hooks can only be called inside of the body of a function component. ошибку.

Итак, как я запускаю пользовательский метод крючка с помощью нажатия кнопки?

Ответ №1:

Я думаю, что когда вы вызовете useAuth, он вернет функцию, которую вы хотите вызвать позже.

Например, после

 const [password, setPassword] = useState('');
 

вы можете положить

 const [password, setPassword] = useState('');
const auth = useAuth();
 

Затем вы можете вызвать auth() в функции входа, вместо того, чтобы вызывать useAuth там.

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