ruby-on-rails - React rails authentication - 无需重新加载页面即可获取用户状态
问题描述
我正在使用后端的 Rails API 和前端的 React 构建一个 SPA。用户身份验证按需要工作,我正在从 rails 获取用户状态。问题是当用户登录应用程序时,我必须手动刷新整个浏览器才能更新状态。
// App.js
function userReducer(state, action) {
switch (action.type) {
case "success": {
return {
...state,
id: action.id,
username: action.username,
email: action.email,
logged_in: action.status,
error: ""
};
}
case "fail": {
return {
...state,
id: "",
username: "",
email: "",
logged_in: false,
error: action.error
};
}
default:
return state;
}
}
// set initial state of the logged in user
const intialUserState = {
id: "",
username: "",
email: "",
logged_in: false,
error: ""
};
export const UserStatus = React.createContext(intialUserState);
function App() {
const [userState, dispatch] = useReducer(userReducer, intialUserState);
// fetch the user's data
function fetchLoggedInUserData() {
axios
.get("http://localhost:3000/api/v1/logged_in", { withCredential: true })
.then(response => {
const { id, username, email, logged_in } = response.data;
if (response.status === 200) {
dispatch({
type: "success",
id: id,
username: username,
email: email,
status: logged_in
});
}
})
.catch(error => {
dispatch({ type: "fail", error: error });
});
}
// when the app loads, check if the user is signed in or not.
// if the user is signed in, then store the user's data into the state
useEffect(() => {
fetchLoggedInUserData();
}, []);
return (
<UserStatus.Provider value={{ userState, dispatch }}>
<Router>
<>
<Switch>
<Route path="/admin" component={Admin} />
<Route path="/" render={props => <Public {...props} />} />
</Switch>
</>
</Router>
</UserStatus.Provider>
);
}
上面的代码按预期工作,我可以存储您从代码中看到的用户状态。问题是当用户单击提交按钮时,我想自动存储用户而无需刷新页面。下面的代码来自Login.js
// Login.js
function signinReducer(state, action) {
switch (action.type) {
case "field": {
return {
...state,
[action.field]: action.value
};
}
case "signin": {
return {
...state,
error: "",
isLoading: true
};
}
case "success": {
return {
...state,
error: "",
isLoading: false
};
}
case "error": {
return {
...state,
isLoading: false,
error: action.error
};
}
}
}
const initialState = {
username: "",
password: "",
isLoading: false,
error: ""
};
function FormMain() {
const [signinState, dispatch] = useReducer(signinReducer, initialState);
const { username, password, isLoading, error } = signinState;
const handleSubmit = async e => {
e.preventDefault();
dispatch({ type: "signin" });
await postUserData();
};
function postUserData() {
axios
.post(
"http://localhost:3000/api/v1/sessions",
{
user: {
username: username,
password: password
}
},
{ withCredentials: true }
)
.then(response => {
if (response.status === 200) {
dispatch({ type: "success" });
}
})
.catch(error => {
// dispatch({ type: "error", error: error.response.data[0] });
});
}
}
我已经从上面的代码中删除了登录表单,因为它太长了。解决方案可以以某种方式将状态从Login.js
to转移App.js
或直接更新App.js
from the的状态Login.js
并使用useEffect
in App.js
,并更新状态而无需手动刷新浏览器,但我不知道该怎么做。
解决方案
通过创建一个新case
的 toApp.js
并case
从Login.js
.
// App.js
function userReducer(state, action) {
switch (action.type) {
case "success": {
return {
...state,
id: action.id,
username: action.username,
email: action.email,
admin: action.admin,
logged_in: action.status,
error: ""
};
}
case "fail": {
return {
...state,
id: "",
username: "",
email: "",
admin: false,
logged_in: false,
error: action.error
};
}
case "globalFetch": {
return {
...state,
id: action.id,
username: action.username,
email: action.email,
admin: action.admin,
logged_in: action.status,
error: ""
};
}
default:
return state;
}
}
如您所见,globalFetch
可以轻松地将案例传递给Login.js
通过 useContext,然后根据您的要求更新案例。
// Login.js
function postUserData() {
axios
.post(
"http://localhost:3000/api/v1/sessions",
{
user: {
username: username,
password: password
}
},
{ withCredentials: true }
)
.then(response => {
if (response.status === 200) {
const { id, username, email, logged_in, admin } = response.data;
dispatch({ type: "success" });
state.dispatch({
type: "globalFetch",
id: id,
username: username,
email: email,
admin: admin,
status: logged_in
});
}
})
.catch(error => {
// dispatch({ type: "error", error: error.response.data[0] });
});
}
// More code...
}
推荐阅读
- node.js - 在 express 节点 js 中访问令牌身份验证(没有 jwt 或护照)
- javascript - Phaser P2 Player 踢球并在击球时添加 Impulse
- macos - Docker 容器连接拒绝 MacOS
- php - 从关系中获取独特的任务
- php - Laravel 无法从正确的文件中导入类,它在控制器中查找
- angular - Ionic 4 (Angular 7) - 共享组件问题
- amazon-web-services - AWS Lambda 访问被拒绝
- linux - 即使安装新版本并删除旧版本后也无法修改 gcc 版本
- vb.net - 我如何通过从另一个表中选择特定字段的数据插入表中
- javafx - 如何创建 Javafx 保存、从文本文件中读取信息并让用户编辑他们的信息