javascript - 在属性更新后更新用户上下文 - AWS Amplify

标签 javascript reactjs amazon-web-services aws-amplify react-context

我有一个要求,即首次向用户显示他们需要在登录后同意的弹出窗口。我在 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/

相关文章:

javascript - 迭代对象属性并修改它们

javascript - 为多个子组件或简单的父组件添加事件监听器

html - 图像高度和宽度的CSS问题

reactjs - 在 GraphQL/Relay 中处理隐私

amazon-web-services - ID 为 X 的堆栈不存在或已被删除 - cfn-init

java - 在 c4.large AWS 实例中运行的 Java 应用程序性能低下

javascript - 如何通过 createTextNode() 使用列表的第一个子元素

JavaScript 仅在 Squarespace 中被调用一次

amazon-web-services - 在 Amazon S3 中删除文件的最快方法

javascript - Perf 未定义 - 使用 webpack-dev-server 运行 React 应用程序