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 挂钩)从操作中返回承诺?