React-redux挂钩和功能组件逻辑

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了React-redux挂钩和功能组件逻辑相关的知识,希望对你有一定的参考价值。

我正在尝试通过登录页面来掌握react / redux的知识,以扩展我的知识。我遇到以下错误的问题:

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

我知道这已经张贴在这里很多,但是没有答案适合我。我可以让商店在应用程序的其他部分正常工作,只是这里的逻辑有些麻烦。任何帮助表示赞赏。我的登录页面是这个:

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请求:

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 };
答案

LoginUser不是React组件,它只是一个处理事件的函数。并且,如消息所言,除非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>
}

以上是关于React-redux挂钩和功能组件逻辑的主要内容,如果未能解决你的问题,请参考以下文章

redux超易学三篇之三(一个逻辑完整的react-redux)

动手实现 React-redux:connect 和 mapStateToProps

如何使用 thunk 和 useDispatch(react-redux 挂钩)从操作中返回承诺?

运行/调试你的PHP代码

ReactJS:如何只调用一次 useEffect 挂钩来获取 API 数据

如何使用 thunk 在 react-redux 挂钩中进行异步调用?