React-redux Hooks и функциональная логика компонентов - PullRequest
0 голосов
/ 10 января 2020

Я пытаюсь освоить реакцию / редукцию на странице входа, чтобы расширить свои знания. У меня возникли некоторые проблемы со следующей ошибкой:

Invalid hook call. Hooks can only be called inside of the body of a function component.

Я знаю, что это было опубликовано здесь много, но ни один из ответов не залипает для меня. я могу заставить магазин работать нормально в других частях приложения, просто возникли проблемы с логикой c здесь. любая помощь приветствуется. Моя страница входа в систему выглядит следующим образом:

import React, { useState } from "react";
import { Grid, CircularProgress, Typography, Button, Tabs, Tab, TextField, Fade } from "@material-ui/core";
import { withRouter } from "react-router-dom";
import useStyles from "./styles";
import logo from "./logo.svg";
import { LoginUser } from "../../comps/Userauth";

function Login(props) {
  var classes = useStyles();
  var [isLoading, setIsLoading] = useState(false);
  var [error, setError] = useState(null);
  var [activeTabId, setActiveTabId] = useState(0);
  var [loginValue, setLoginValue] = useState("");
  var [passwordValue, setPasswordValue] = useState("");
  return (
    <Grid container className={classes.container}>
      <div className={classes.logotypeContainer} style={{zIndex: '1'}} >
        <img src={logo} alt="logo" className={classes.logotypeImage} />
        <Typography className={classes.logotypeText}>test app</Typography>
      </div>
      <div className={classes.formContainer}>
        <div className={classes.form}>
          <Tabs
            value={activeTabId}
            onChange={(e, id) => setActiveTabId(id)}
            indicatorColor="primary"
            textColor="primary"
            centered
          >
            <Tab label="Login" classes={{ root: classes.tab }} />
          </Tabs>
          {activeTabId === 0 && (
            <React.Fragment>
              <Fade in={error}>
                <Typography color="secondary" className={classes.errorMessage}>
                  Please try again.

                </Typography>
              </Fade>
              <TextField
                id="username"
                InputProps={{
                  classes: {
                    underline: classes.textFieldUnderline,
                    input: classes.textField,
                  },
                }}
                value={loginValue}
                onChange={e => setLoginValue(e.target.value)}
                margin="normal"
                placeholder="Username"
                type="text"
                fullWidth
              />
              <TextField
                id="password"
                InputProps={{
                  classes: {
                    underline: classes.textFieldUnderline,
                    input: classes.textField,
                  },
                }}
                value={passwordValue}
                onChange={e => setPasswordValue(e.target.value)}
                margin="normal"
                placeholder="Password"
                type="password"
                fullWidth
              />
              <div className={classes.formButtons}>
                {isLoading ? (
                  <CircularProgress size={26} className={classes.loginLoader} />
                ) : (
                  <Button
                    disabled={
                      loginValue.length === 0 || passwordValue.length === 0
                    }
                    onClick={() =>
                      LoginUser(
                        loginValue,
                        passwordValue,
                        props.history,
                        setIsLoading,
                        setError,
                      )
                    }
                    variant="contained"
                    color="primary"
                    size="large"
                  >
                    Login
                  </Button>
                )}
              </div>
            </React.Fragment>
          )}
        </div>
      </div>
    </Grid>
  );
}
export default withRouter(Login);

И userauth req:

import React from "react";
import axios from "axios";
import {useSelector, useDispatch} from 'react-redux'
import allActions from '../actions'
var jwtDecode = require('jwt-decode');

function LoginUser(login, password, history, setIsLoading, setError) {
    const currentUser = useSelector(state => state.currentUser)
    const dispatch = useDispatch()
  try {
  setError(false);
  setIsLoading(true);
  axios.post('/login', {username: login, password: password}, {
  }).catch(function (error) {
    if (error.response) {
        setError(true);
      console.log(error.response.data);
      console.log(error.response.status);
      console.log(error.response.headers);
    } else if (error.request) {
        setError(true);
      console.log(error.request);
    } else {
        setError(true);
      console.log('Error', error.message);
    }
  }).then(function(response) {
    if (response.status == '200') {
      setTimeout(() => {
        setError(null)
        setIsLoading(false)
        let token1 = jwtDecode(response.data.token);
        dispatch(allActions.userActions.setUser(token1.username))
        history.push('/app/dashboard')
      }, 2000);
    } else {
      setError(true);
      setIsLoading(false);
    }  
  })
} catch (error) {
  setError(true);
  setIsLoading(false);
}
}
function signOut(dispatch, history) {
  dispatch(allActions.userActions.logOut())
  history.push("/login");
}
export { LoginUser, signOut };

1 Ответ

1 голос
/ 10 января 2020

LoginUser не является компонентом React, это просто функция, которая обрабатывает событие. И, как говорится в сообщении, вы не можете использовать ловушки, если реакция не рендерит компонент.

Вы должны будете либо передать все, что нужно вашей функции входа в систему, в качестве аргументов, либо сделать рефакторинг.

Один из способов рефакторинга - создание настраиваемого хука, который предоставляет вам эту функцию входа в систему.

export default useLoginHandler(history, setIsLoading, setError) {
  const currentUser = useSelector(state => state.currentUser)
  const dispatch = useDispatch()

  return {
    onLogin(login, password) {
      doStuff().then(() => {
        // use values from above hooks
        dispatch(yourActionMaker(whatever))
      })
    },
    onLogout() {
      dispatch(allActions.userActions.logOut())
      history.push("/login");
    },
  }
}

Теперь в вашем компоненте используйте его, как и любой другой хук:

function Login(props) {
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState(null);

  const {onLogin, onLogOut} = useLoginHandler(props.history, setIsLoading, setError)

  // other hooks...

  return <React.Fragment>
    {/* other rendering... */}
    <div onClick={() => onLogin(loginValue, passwordValue)}>
      login
    </div>
  </React.Fragment>
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...