我正在构建一个 Web 应用程序 Reactjs 和 Redux,您可以在其中登录仪表板,然后可以注销。 我使用“redux-react-session”来管理 session ,并在 userActions.js 中创建了一个名为 logoutUser 的操作。此操作在 Dashboard.jsx 中导入并调用,我在其中添加了带有 onClick 事件的注销按钮。我期望的是,当我点击注销时,它应该只是将我重定向到主页('/')
我的问题是:每当我单击注销按钮时,它会将我重定向到主页(“/”),然后刷新回仪表板。
控制台.dev 错误:
Uncaught Error: Actions must be plain objects. Instead, the actual type was: 'undefined'. You may need to add middleware to your store setup to handle dispatching other values, such as 'redux-thunk' to handle dispatching functions.
userAction.js:
import axios from 'axios'
import { sessionService } from 'redux-react-session'
export const loginUser = (credentials, navigate, setFieldError, setSubmitting) => {
//make checks and get some data
return () => {
axios.post("http://localhost:5000/api/form/signin",
credentials,
{
headers: {
"Content-Type": "application/json"
}
}
).then((response) => {
const { data } = response;
if (data.status === "FAILED") {
const { message } = data;
//check for specific error
if (message.includes("credentials")) {
setFieldError("email", message);
setFieldError("password", message);
} else if (message.includes("password")) {
setFieldError("password", message);
alert("Wrong email or password")
}
} else if (data.status === "SUCCESS") {
const userData = data.data;
const token = userData._id;
sessionService.saveSession(token)
.then(() => {
sessionService.saveUser(userData)
.then(() => {
if (userData.role === "admin") {
navigate("/dashboard")
} else if (userData.role === "user") {
navigate("/joblist")
} else {
navigate("/")
alert("Role is not known, please contact Admin or make a new account!")
sessionService.deleteSession(token)
}
})
.catch(err => console.error(err))
})
.catch(err => console.error(err))
}
})
.catch(err => { console.error(err) });
}
}
export const signupUser = (credentials, navigate, setFieldError, setSubmitting) => {
return (dispatch) => {
axios.post("http://localhost:5000/api/form/signup",
credentials,
{
headers: {
"Content-Type": "application/json"
}
}
).then((response) => {
const { data } = response;
if (data.status === 'FAILED') {
const { message } = data;
//check for specific error
if (message.includes("name")) {
setFieldError("name", message);
} else if (message.includes("email")) {
setFieldError("email", message);
} else if (message.includes("date")) {
setFieldError("dateOfBirth", message);
} else if (message.includes("password")) {
setFieldError("password", message);
}
//complete submission
setSubmitting(false);
} else if (data.status === "SUCCESS") {
//Login user after successfull signup
const { email, password } = credentials;
dispatch(loginUser({ email, password }, navigate, setFieldError, setSubmitting))
}
})
.catch(err => console.error(err));
}
}
export const logoutUser = (navigate) => {
return () => {
sessionService.deleteSession();
sessionService.deleteUser();
navigate('/');
}
}
仪表板.jsx:
import {
StyledTitle,
StyledSubTitle,
Avatar,
StyledButton,
ButtonGroup,
StyledFormArea,
colors
} from './../../components/Styles';
//Formik
import { Formik, Form } from 'formik';
import { TextInput } from '../../components/FormLib';
//Logo
import Logo from './../../assets/logo.png';
//auth & redux
import { connect } from 'react-redux';
import { logoutUser } from '../../auth/actions/userActions';
//React router
import { useNavigate } from 'react-router-dom';
import { useDispatch } from 'react-redux';
const Dashboard = ({ logoutUser }) => {
const navigate = useNavigate();
const dispatch = useDispatch();
return (
<div>
<div>
<Avatar image={Logo} />
</div>
<StyledFormArea bg={colors.dark2} style={{ marginLeft: '-400px' }}>
<StyledTitle size={65}>Welcome to Dashboard </StyledTitle>
<StyledSubTitle size={27}>Feel free to post new jobs</StyledSubTitle>
<Formik
initialValues={{
title: '',
description: ''
}}
>
<Form>
<TextInput
name="title"
type="text"
label="Title :"
placeholder="Job Title"
/>
<TextInput
name="description"
type="text"
label="Description :"
placeholder="Job description"
/>
</Form>
</Formik>
<ButtonGroup>
<StyledButton to="#">Post Job</StyledButton>
<StyledButton
bg={colors.red}
to="#"
onClick={()=> dispatch(logoutUser(navigate))}
>
Logout
</StyledButton>
</ButtonGroup>
</StyledFormArea>
</div>
);
};
export default connect(null, { logoutUser })(Dashboard);
Store.js:
import { createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers/rootReducer';
import {sessionService} from 'redux-react-session';
const initialState = {}
const middlewares = [thunk]
const store = createStore(rootReducer, initialState, compose(applyMiddleware(...middlewares)));
sessionService.initSessionService(store);
export default store;
编辑:
如果我在操作中添加return()
:
export const logoutUser = (navigate) => {
return () => {
sessionService.deleteSession();
sessionService.deleteUser();
navigate('/');
}
}
我在 Console.dev 中收到此错误:
Uncaught TypeError: logoutUser(...) is not a function
编辑(2):
删除 logoutUser(navigate)( )
的 return ( ) => {
... }
和 ( )
code> 将保持页面刷新然后让我返回仪表板
最佳答案
问题似乎与使用connect
高阶组件和手动向商店分派(dispatch)操作有关。 connect
HOC 自动将操作创建者包装在对 dispatch
的调用中,并将可分派(dispatch)操作作为 prop 注入(inject)到装饰组件中。然后,您的代码将 logoutUser
包装在对 dispatch
的另一个调用中。选择其中之一,但不能同时选择两者。
使用连接
HOC
//auth & redux
import { connect } from 'react-redux';
import { logoutUser } from '../../auth/actions/userActions';
//React router
import { useNavigate } from 'react-router-dom';
...
const Dashboard = ({ logoutUser }) => {
const navigate = useNavigate();
return (
<div>
...
<StyledFormArea bg={colors.dark2} style={{ marginLeft: '-400px' }}>
<StyledTitle size={65}>Welcome to Dashboard </StyledTitle>
<StyledSubTitle size={27}>Feel free to post new jobs</StyledSubTitle>
...
<ButtonGroup>
<StyledButton to="/">Post Job</StyledButton>
<StyledButton
bg={colors.red}
to="/" // <-- fix target from "#" to "/"
onClick={(e) => {
e.preventDefault(); // <-- prevent any default button actions
logoutUser(navigate); // <-- call decorated action
}}
>
Logout
</StyledButton>
</ButtonGroup>
</StyledFormArea>
</div>
);
};
const mapDispatchToProps = {
logoutUser
};
export default connect(null, mapDispatchToProps)(Dashboard);
使用useDispatch
钩子(Hook)
//auth & redux
import { useDispatch } from 'react-redux';
import { logoutUser } from '../../auth/actions/userActions';
//React router
import { useNavigate } from 'react-router-dom';
...
const Dashboard = () => {
const navigate = useNavigate();
const dispatch = useDispatch();
return (
<div>
...
<StyledFormArea bg={colors.dark2} style={{ marginLeft: '-400px' }}>
<StyledTitle size={65}>Welcome to Dashboard </StyledTitle>
<StyledSubTitle size={27}>Feel free to post new jobs</StyledSubTitle>
...
<ButtonGroup>
<StyledButton to="/">Post Job</StyledButton>
<StyledButton
bg={colors.red}
to="/" // <-- fix target from "#" to "/"
onClick={(e) => {
e.preventDefault(); // <-- prevent any default button actions
dispatch(logoutUser(navigate)); // <-- dispatch action
}}
>
Logout
</StyledButton>
</ButtonGroup>
</StyledFormArea>
</div>
);
};
export default Dashboard;
错误消息似乎还表明您尚未将任何异步操作中间件添加到您的 redux 存储中。
You may need to add middleware to your store setup to handle dispatching other values, such as 'redux-thunk' to handle dispatching functions.
我建议按照 redux
和 react-redux
指南将其添加到您的商店配置中,或更新到 redux-toolkit
(< em>相同的维护者),其中包括开箱即用的 thunk 中间件,因为它是一个常见的用例。
关于reactjs - 未捕获错误 : Actions must be plain objects. 相反,实际类型为: 'undefined',我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72645333/