【问题标题】:AWS Amplify in React, how can I render the new data from the subscribed listenerAWS Amplify in React,如何从订阅的侦听器呈现新数据
【发布时间】:2021-07-06 09:27:14
【问题描述】:

我正在开发一个 React 项目并使用 AWS Amplify 作为无服务器后端的工具,其中我有一个 DynamoDB 作为我在 AWS 云中的数据库。

我的 React 应用需要检测 DynamoDB 中的实时数据更新。我正在使用 Amplify 的 GraphQL API。

Amplify 生成的 GraphQL API 提供了一个subscriptions API,用于实时订阅数据更改。我认为这正是我需要的,所以我正在使用它:

import React, {useEffect, useState, useRef} from 'react';
import Amplify, { API, graphqlOperation } from 'aws-amplify';
import { onCreateData } from './graphql/subscriptions';

// subscribe to listen to new data creation in DynamoDB
const subscription = API.graphql(
    graphqlOperation(onCreateData)
).subscribe({
    next: (newData) => {
      // New data is received here outside 'App' functional component,
      // how can I render the data then?
      console.log(`new data: ${JSON.stringify(newData)}`);
      
    }
});

// I can't put the above subscription code inside App component, I don't know why but it just doesn't work unless I move it outside the App functional component.

function App() {
  const [dataArray, setDataArray] = useState([]);
   ...

  useEffect(() => {
    fetchDataArray();
    showDataArray();
    return () => {
      //cleanup
    }
  }, [dataArra])

  return (<div>
    <canvas ref={canvasRef}/>
  </div>)
}

export default App;

问题是 subscription 用于 DynamoDB 中的新数据插入仅在我将其放在 function App(){...} 之外时才有效,如上所示。那么,当订阅回调next: (newData)收到newData时,如何在App组件中显示新数据?

你可以在我的App 组件中看到我有状态变量dataArray,理想的解决方案是用newData 更新这个dataArray 状态,但我认为现在不可能。所以,总的来说,我想知道现在如何在我的App 组件中显示新数据?

附: Amplify GraphQL API doc sample code(如果您看到“订阅”部分)也显示订阅代码与导入处于同一级别。

【问题讨论】:

  • 学习一些教程? react FC(你的App是FC,可以转成类组件)需要像useSubscription-apollographql.com/docs/react/data/subscriptions这样的hook形式
  • 我想知道如何订阅我的功能组件,而不是类组件。有没有可能。
  • 您是否尝试在 App 中使用 useEffect 挂钩添加它?

标签: reactjs amazon-web-services graphql amazon-dynamodb aws-amplify


【解决方案1】:

我们在我们的项目中使用 amplify,我们的一个示例是下面的简单聊天功能:

interface ChatMessagesProps {
  internal?: boolean
  convoId: string
}

export const ChatMessages: FC<ChatMessagesProps> = ({ internal, convoId }) => {
  const classes = useStyles()
  const {
    appState: { user }
  } = useAppState()

  let [messages, setMessages] = useState<any>([])
  let [currentConversationId, setConversationId] = useState<string>(convoId)
  const listRef = useRef<VariableSizeProps>()

  let subscription = useRef<ISubscriptionObject | null>(null)
  let updateSubscription = useRef<ISubscriptionObject | null>(null)

  const addNewMessage = ({ onCreateMessage }) => {
    console.log(onCreateMessage)
    // from here we can do whatever we want with the data within the context of this component
  }

  const messageUpdated = ({ onUpdateMessage }) => {
    console.log(onUpdateMessage)
    // from here we can do whatever we want with the data within the context of this component
  }

  const getConversationDetails = async () => {
    subscription.current = graphQLSubscription(
      onCreateMessage,
      { conversationId: currentConversationId },
      addNewMessage
    )

    updateSubscription.current = graphQLSubscription(
      onUpdateMessage,
      { conversationId: currentConversationId },
      messageUpdated
    )
  }

  useEffect(() => {
    if (currentConversationId) {
      getConversationDetails()
    }
    return () => {
      subscription?.current?.unsubscribe()
      updateSubscription?.current?.unsubscribe()
    }
  }, [currentConversationId])

  return (
    <div className={classes.root}>
      <MessageList listRef={listRef} messages={messages} internal={internal} />
      <MessageInput userId={user?.id || ''} internal={internal} conversationId={currentConversationId} />
    </div>
  )
}

const useStyles = makeStyles(() => ({
  root: {
    width: '100%',
    height: '100%',
    backgroundColor: 'white',
    position: 'relative'
  }
}))

我们使用助手graphQLSubscription

export const graphQLSubscription = (subscription: string, options: any, callback: (d: any) => void) => {
  return API.graphql(graphqlOperation(subscription, options)).subscribe({
    next: ({ value: { data, errors } }) => {
      console.log(errors)
      callback(data)
    }
  })
}

对于您的示例代码,您只想将订阅存储在 ref 中,以便能够在卸载时取消订阅

import React, {useEffect, useState, useRef} from 'react';
import Amplify, { API, graphqlOperation } from 'aws-amplify';
import { onCreateData } from './graphql/subscriptions';

function App() {
  const [dataArray, setDataArray] = useState([]);
  const subscriptionRef = useRef()
   ...

  useEffect(() => {
    fetchDataArray();
    showDataArray();

    subscriptionRef.current = API.graphql(
      graphqlOperation(onCreateData)
    ).subscribe({
      next: (newData) => {
        // New data is received here outside 'App' functional component,
        // how can I render the data then?
        console.log(`new data: ${JSON.stringify(newData)}`);
      }
    });

    return () => {
      //cleanup
      subscriptionRef.current.unsubscribe()
    }
  }, [dataArra])

  return (<div>
    <canvas ref={canvasRef}/>
  </div>)
}

export default App;

您可以从那里将其提取到组件内或您的项目中的辅助函数中

【讨论】:

    猜你喜欢
    • 2019-04-24
    • 2020-12-28
    • 1970-01-01
    • 1970-01-01
    • 2020-10-21
    • 2021-11-25
    • 2018-12-12
    • 2020-11-09
    • 2022-01-13
    相关资源
    最近更新 更多