我有一个要求,即首次向用户显示他们需要在登录后同意的弹出窗口。我在 Cognito 中创建了一个标记为"is"的自定义属性,直到用户单击同意按钮。所有这些逻辑都有效,但当您刷新页面时,尽管用户同意并在 Cognito 中更改了属性,但仍会再次向用户显示弹出窗口。
我正在使用带有 useContext 钩子(Hook)的 React context api。我在 React 工具中注意到上下文没有得到更新,这可能是问题所在。
AuthContext.js
import React from 'react';
export const AuthContext = React.createContext();
export const AuthProvider = AuthContext.Provider;
App.js
import React from 'react';
import { withRouter } from 'react-router-dom';
import Header from './components/Header';
import Routes from './Routes';
import useAmplifyAuth from './libs/useAmplifyAuth';
import { AuthProvider } from './context/AuthContext';
import InitialLoginModal from './components/InitialLoginModal';
function App() {
const {
state: { user },
handleSignout
} = useAmplifyAuth();
return (
<>
<AuthProvider value={{ user, handleSignout }}>
<>
<Header />
<Routes />
<InitialLoginModal />
</>
</AuthProvider>
</>
);
}
export default withRouter(App);
InitialLoginModal.js
import React, { useContext, useState, useEffect } from 'react';
import { Modal, Button, Image } from 'react-bootstrap';
import { Auth } from 'aws-amplify';
import imgLogo from '../img/logo.jpg';
import { AuthContext } from '../context/AuthContext';
const InitialLoginModal = () => {
const { user, handleSignout } = useContext(AuthContext);
const [showModal, setShowModal] = useState(false);
const [initialLogin, setInitialLogin] = useState('');
const noAccept = () => {
setShowModal(false);
handleSignout();
};
useEffect(() => {
if (user) {
console.log(user.attributes['custom:initiallogin']);
if (user.attributes['custom:initiallogin'] === 'Yes') {
setShowModal(true);
}
}
}, [user]);
const accept = () => {
updateInitialLogin();
setShowModal(false);
};
const updateInitialLogin = async () => {
await Auth.updateUserAttributes(user, { 'custom:initiallogin': 'No' });
setInitialLogin('No');
setShowModal(false);
};
return (
<>
{/* Initial login modal */}
<Modal
show={showModal}
onHide={noAccept}
dialogClassName="modal-70w modal-item"
aria-labelledby="Initial Login Modal"
>
<Modal.Header closeButton>
<Modal.Title>
<Image
src={imgLogo}
alt="Logo"
fluid
className="modal-image-center"
/>
</Modal.Title>
</Modal.Header>
<Modal.Body>
<p>
Text that I must agree to.
</p>
</Modal.Body>
<Modal.Footer>
<Button onClick={accept}>Next</Button>
</Modal.Footer>
</Modal>
</>
);
};
export default InitialLoginModal;
使用AmplifyAuth.js
import { useReducer, useState, useEffect } from 'react';
import { Auth, Hub } from 'aws-amplify';
const amplifyAuthReducer = (state, action) => {
switch (action.type) {
case 'FETCH_USER_DATA_INIT':
return {
...state,
isLoading: true,
isError: false
};
case 'FETCH_USER_DATA_SUCCESS':
return {
...state,
isLoading: false,
isError: false,
user: action.payload.user
};
case 'FETCH_USER_DATA_FAILURE':
return { ...state, isLoading: false, isError: true };
case 'RESET_USER_DATA':
return { ...state, user: null };
default:
throw new Error();
}
};
const useAmplifyAuth = () => {
const initialState = {
isLoading: true,
isError: false,
user: null
};
const [state, dispatch] = useReducer(amplifyAuthReducer, initialState);
const [triggerFetch, setTriggerFetch] = useState(false);
useEffect(() => {
let isMounted = true;
const fetchUserData = async () => {
if (isMounted) {
dispatch({ type: 'FETCH_USER_DATA_INIT' });
}
try {
if (isMounted) {
const data = await Auth.currentAuthenticatedUser();
if (data) {
dispatch({
type: 'FETCH_USER_DATA_SUCCESS',
payload: { user: data }
});
}
}
} catch (error) {
if (isMounted) {
dispatch({ type: 'FETCH_USER_DATA_FAILURE' });
}
}
};
const HubListener = () => {
Hub.listen('auth', data => {
const { payload } = data;
onAuthEvent(payload);
});
};
const onAuthEvent = payload => {
switch (payload.event) {
case 'signIn':
if (isMounted) {
setTriggerFetch(true);
console.log('signed in');
}
break;
default:
return;
}
};
HubListener();
fetchUserData();
return () => {
Hub.remove('auth');
isMounted = false;
};
}, [triggerFetch]);
const handleSignout = async () => {
try {
console.log('signed out');
await Auth.signOut();
setTriggerFetch(false);
dispatch({ type: 'RESET_USER_DATA' });
} catch (error) {
console.error('Error signing out user ', error);
}
};
return { state, handleSignout };
};
export default useAmplifyAuth;
最后,我只需要用户能够同意条款,更新他们的自定义属性,然后不再显示模态。任何帮助,将不胜感激。谢谢。
- 根据@vencovsky 建议新建 InitialLoginModal.js
import React, { useContext, useEffect, useState } from 'react';
import { Modal, Button, Image } from 'react-bootstrap';
import { Auth } from 'aws-amplify';
import imgLogo from '../img/logo.jpg';
import { AuthContext } from '../context/AuthContext';
const InitialLoginModal = () => {
const {
user,
handleSignout,
shouldShowModal,
setShouldShowModal
} = useContext(AuthContext);
const [showModal, setShowModal] = useState(shouldShowModal);
// const [initialLogin, setInitialLogin] = useState('');
const noAccept = () => {
setShowModal(false);
handleSignout();
};
useEffect(() => {
if (user) {
if (user.attributes['custom:initiallogin'] === 'Yes') {
setShowModal(true);
}
}
}, [user, setShouldShowModal]);
const accept = () => {
updateInitialLogin();
// setShouldShowModal(false);
};
const updateInitialLogin = async () => {
if (user) {
await Auth.updateUserAttributes(user, { 'custom:initiallogin': 'No' });
setShowModal(false);
}
};
return (
<>
{/* Initial login modal */}
<Modal
show={showModal}
onHide={noAccept}
dialogClassName="modal-70w modal-item"
aria-labelledby="Initial Login Modal"
>
<Modal.Header closeButton>
<Modal.Title>
<Image
src={imgLogo}
alt="Logo"
fluid
className="modal-image-center"
/>
</Modal.Title>
</Modal.Header>
<Modal.Body>
<p>
Info here
</p>
</Modal.Body>
<Modal.Footer>
<Button onClick={accept}>Next</Button>
</Modal.Footer>
</Modal>
</>
);
};
export default InitialLoginModal;
最佳答案
我自己刚遇到这个问题,我相信这是需要更新的行:
const data = await Auth.currentAuthenticatedUser();
到:
const data = await Auth.currentAuthenticatedUser({bypassCache: true});
这将直接从 Cognito 检索更新的属性,以便在属性设置为 custom:initiallogin = 'No' 时不会向用户显示模态。
关于javascript - 在属性更新后更新用户上下文 - AWS Amplify,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57412631/