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

时间:2019-09-04 08:37:40

标签: reactjs apollo react-apollo apollo-client

我正在建立一个不和谐/松弛的克隆。我有频道,消息和用户。 当我的聊天组件加载后,便会通过Apollo的useQuery钩子获取频道。

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

在较小的Channel.js组件中,我将单击的Channel的channelid写入了阿波罗缓存。效果很好,我在Messages.js组件中使用了useQuery钩@client来从缓存中获取通道ID,并且效果很好。

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

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

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

useLazyQuery确实给了我无限循环,如前所述。

我真的在为阿波罗/反应钩的条件而苦苦挣扎...

/// Channel.js组件///


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组件///


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的数据中包含消息...但是请在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.

3 个答案:

答案 0 :(得分:2)

您在每个渲染器上调用fetchMessages。 尝试将fetchMessages放在useEffect中:

useEffect(() => {
    if (!channelidLoading && channelidData) {
        fetchMessages();
    }

}, [channelidLoading, channelidData]);

就像fetchMessages函数仅在 channelidLoading或channelidData正在更改。

答案 1 :(得分:2)

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

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

答案 2 :(得分:0)

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

   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 },
    });
  }