redux - 为什么,在 Redux 中使用 useEffect() 和 .then() 时,我得到一个错误:Actions must be plain objects。使用自定义中间件进行异步操作
问题描述
使用 Redux,现在我在使用 oauth 时遇到了登录和注销按钮。
当我按下按钮登录时,会出现弹出窗口,我可以选择一个帐户。但与此同时,网页会引发错误。
如标题中所述,我收到以下错误:错误:操作必须是普通对象。使用自定义中间件进行异步操作。我正在使用钩子,在这种情况下使用 useEffect().then() 来获取数据。
1)为什么?
2)也不知道,为什么我会收到警告:'onAuthChange' 函数使 useEffect Hook(第 35 行)的依赖关系在每次渲染时都发生变化。将它移到 useEffect 回调中。或者,将“onAuthChange”定义包装到它自己的 useCallback() Hook react-hooks/exhaustive-deps
这是我的代码:
GoogleAuth.js
import React, { useEffect } from "react";
import { useSelector, useDispatch } from "react-redux";
import { signIn, signOut } from "../actions";
const API_KEY = process.env.REACT_APP_API_KEY;
const GoogleAuth = () => {
const isSignedIn = useSelector((state) => state.auth.isSignedIn);
console.log("IsSignedIn useSelector: " + isSignedIn);
const dispatch = useDispatch();
const onAuthChange = () => {
if (isSignedIn) {
dispatch(signIn());
} else {
dispatch(signOut());
}
};
useEffect(
() => {
window.gapi.load("client:auth2", () => {
window.gapi.client
.init({
clientId: API_KEY,
scope: "email"
})
.then(() => {
onAuthChange(window.gapi.auth2.getAuthInstance().isSignedIn.get());
console.log("isSignedIn.get(): " + window.gapi.auth2.getAuthInstance().isSignedIn.get());
window.gapi.auth2.getAuthInstance().isSignedIn.listen(onAuthChange);
});
});
},
[ onAuthChange ]
);
const onSignInOnClick = () => {
dispatch(window.gapi.auth2.getAuthInstance().signIn());
};
const onSignOutOnClick = () => {
dispatch(window.gapi.auth2.getAuthInstance().signOut());
};
const renderAuthButton = () => {
if (isSignedIn === null) {
return null;
} else if (isSignedIn) {
return (
<button onClick={onSignOutOnClick} className="ui red google button">
<i className="google icon" />
Sign Out
</button>
);
} else {
return (
<button onClick={onSignInOnClick} className="ui red google button">
<i className="google icon" />
Sign In with Google
</button>
);
}
};
return <div>{renderAuthButton()}</div>;
};
export default GoogleAuth;
减速器/index.js
import { combineReducers } from "redux";
import authReducer from "./authReducer";
export default combineReducers({
auth: authReducer
});
减速器/authReducer.js
import { SIGN_IN, SIGN_OUT } from "../actions/types";
const INITIAL_STATE = {
isSignedIn: null
};
export default (state = INITIAL_STATE, action) => {
switch (action.type) {
case SIGN_IN:
return { ...state, isSignedIn: true };
case SIGN_OUT:
return { ...state, isSignedIn: false };
default:
return state;
}
};
动作/index.js
import { SIGN_IN, SIGN_OUT } from "./types";
export const signIn = () => {
return {
type: SIGN_IN
};
};
export const signOut = () => {
return {
type: SIGN_OUT
};
};
类型.js
export const SIGN_IN = "SIGN_IN";
export const SIGN_OUT = "SIGN_OUT";
解决方案
第一个错误的原因是,在onSignInOnClick
and内部onSignInOnClick
,都dispatch()
接收到 a Promise
(因为window.gapi.auth2.getAuthInstance().signIn()
返回 a Promise
)。在 redux 中处理效果有不同的解决方案,最简单的是redux promise或redux thunk。否则,您可以调度该{ type: SIGN_IN }
操作,并编写一个自定义中间件来处理它。
第二个错误的原因是 onAuthChange 在每次渲染时都被重新定义,你可以在这里看到:
const f = () => () => 42
f() === f() // output: false
这是修复警告的可能解决方案:
useEffect(() => {
const onAuthChange = () => {
if (isSignedIn) {
dispatch(signIn())
} else {
dispatch(signOut())
}
}
window.gapi.load('client:auth2', () => {
window.gapi.client
.init({
clientId: API_KEY,
scope: 'email',
})
.then(() => {
onAuthChange(window.gapi.auth2.getAuthInstance().isSignedIn.get())
console.log(
'isSignedIn.get(): ' +
window.gapi.auth2.getAuthInstance().isSignedIn.get(),
)
window.gapi.auth2.getAuthInstance().isSignedIn.listen(onAuthChange)
})
})
}, [isSignedIn])
推荐阅读
- php - 如何在 laravel 提供者的模型 config.php 文件中动态地将变量名传递给模型
- django - 为什么我不能通过 django-admin 使用我的 Django 实用程序
- java - 如何正确地将 int 值从 firebase 实时数据库检索到 textview?
- azure - 以编程方式进行带有排除项的 Azure 策略分配
- python - 如何在 Pandas Dataframe 中应用 If Else 语句?
- azure - 使用 HTTP 触发器调用逻辑应用时出现 DirectApiRequestHasMoreThanOneAuthorization 错误
- c - read() 不读取套接字缓冲区上的剩余字节
- substrate - 构建错误时出错 [E0282]:需要类型注释
- javascript - jsPDF,来自url的base64图像:未定义dataurl
- python - ValueError:无法将字符串转换为浮点数:'Bad'