首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >useLazyQuery导致过多的重新渲染[Apollo/ apollo/react挂钩]

useLazyQuery导致过多的重新渲染[Apollo/ apollo/react挂钩]
EN

Stack Overflow用户
提问于 2019-09-04 16:37:41
回答 3查看 6.8K关注 0票数 2

我正在构建一个不和谐/松弛的克隆。我有渠道、消息和用户。一旦我的聊天组件加载,频道就会通过useQuery钩子从Apollo获取。

默认情况下,当用户来到聊天组件时,他需要单击特定的频道来查看关于该频道的信息和消息。

在较小的Channel.js组件中,我将单击的Channel的通道In写入apollo缓存。这非常好用,我在Messages.js组件中使用了useQuery钩子@client来从缓存中获取通道it,它工作得很好。

当我使用useLazyQuery钩子来获取特定通道(用户单击的通道)的消息时,问题就出现了。

它会在React中导致无限的重新渲染循环,导致应用程序崩溃。

我尝试过使用带有跳过选项的普通useQuery钩子。然后,我会在需要时调用refetch()函数。这在某种意义上说是“有效”的,因为它不会给我无限循环。但是console.log()给了我这个错误:[GraphQL error]: Message: Variable "$channelid" of required type "String!" was not provided. Path: undefined。这很奇怪,因为我的模式和变量是正确的??

正如前面所说的,useLazyQuery确实给了我无限循环。

我真的很纠结于apollo/react钩子的条件性...

/ Channel.js组件/

代码语言:javascript
复制
const Channel = ({ id, channelName, channelDescription, authorName }) => {
  const chatContext = useContext(ChatContext);

  const client = useApolloClient();
  const { fetchChannelInfo, setCurrentChannel } = chatContext;

  const selectChannel = (e, id) => {
    fetchChannelInfo(true);
    const currentChannel = {
      channelid: id,
      channelName,
      channelDescription,
      authorName
    };
    setCurrentChannel(currentChannel);

    client.writeData({
      data: {
        channelid: id
      }
    });
    // console.log(currentChannel);
  };

  return (
    <ChannelNameAndLogo onClick={e => selectChannel(e, id)}>
      <ChannelLogo className='fab fa-slack-hash' />
      <ChannelName>{channelName}</ChannelName>
    </ChannelNameAndLogo>
  );
};

export default Channel;

/ Messages.js组件/

代码语言:javascript
复制
const FETCH_CHANNELID = gql`
  {
    channelid @client
  }
`;


const Messages = () => {
  const [messageContent, setMessageContent] = useState('');
  const chatContext = useContext(ChatContext);
  const { currentChannel } = chatContext;
  // const { data, loading, refetch } = useQuery(FETCH_MESSAGES, {
  //   skip: true
  // });

  const { data: channelidData, loading: channelidLoading } = useQuery(
    FETCH_CHANNELID
  );

  const [fetchMessages, { data, called, loading, error }] = useLazyQuery(
    FETCH_MESSAGES
  );

  //// useMutation is working
  const [
    createMessage,
    { data: MessageData, loading: MessageLoading }
  ] = useMutation(CREATE_MESSAGE);

  if (channelidLoading && !channelidData) {
    console.log('loading');
    setInterval(() => {
      console.log('loading ...');
    }, 1000);
  } else if (!channelidLoading && channelidData) {
    console.log('not loading anymore...');
    console.log(channelidData.channelid);
    fetchMessages({ variables: { channelid: channelidData.channelid } });
    console.log(data);
  }

我希望有来自useLazyQuery ...But的数据中的消息,而不是在console.log()中获得以下内容:

react-dom.development.js:16408 Uncaught Invariant Violation: Too many re-renders. React limits the number of renders to prevent an infinite loop.

EN

回答 3

Stack Overflow用户

发布于 2019-09-11 14:14:20

您可以在每次渲染时调用fetchMessages。尝试将fetchMessages放在useEffect中:

代码语言:javascript
复制
useEffect(() => {
    if (!channelidLoading && channelidData) {
        fetchMessages();
    }

}, [channelidLoading, channelidData]);

与此类似,只有在channelidLoading或channelidData发生变化时才调用fetchMessages函数。

票数 2
EN

Stack Overflow用户

发布于 2020-01-02 17:14:29

您可以使用useLazyQuery返回的called变量。

!called && fetchMessages({ variables: { channelid: channelidData.channelid } });

票数 2
EN

Stack Overflow用户

发布于 2020-02-13 01:02:40

您还可以考虑执行以下操作:

代码语言:javascript
复制
   import debounce from 'lodash.debounce';
   ...

   const [fetchMessages, { data, called, loading, error }] = useLazyQuery(
    FETCH_MESSAGES
  );
  const findMessageButChill = debounce(fetchMessages, 350);
  ...
  } else if (!channelidLoading && channelidData) {
    findMessageButChill({
       variables: { channelid: channelidData.channelid },
    });
  }
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57784602

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档