react-apollo icon indicating copy to clipboard operation
react-apollo copied to clipboard

useLazyQuery hook sets loading to false before data is updated, breaks the useEffect hook

Open kylehovey opened this issue 4 years ago • 0 comments

The expected behavior is that the loading predicate returned from the useLazyQuery hook should only be false when the data is updated. Since this is used to trigger an effect with useEffect, stale data is used instead of the new data.

The goal is to upload a file using a React-Hooks based component. TinyMCE is used, which takes a file upload handler. The upload requires a URL retrieved from an Apollo Lazy query, which necessitates a useEffect.

const Component = () => {
  const [uploadArgs, setUploadArgs] = useState(null);
  const [getUploadURL, { data, loading, error }] = useLazyQuery(GET_UPLOAD_URL);

  function uploadFile( /* mocked */) {
  }

  function uploadHandler(blob, successCb, failureCb) {
    setUploadArgs([blob, successCb, failureCb]);

    getUploadURL(blob.blobInfo().fileName);
  }

  const [ blob, successCb, failureCb ] = uploadArgs || [];
  const uploadURL = data && data.uploadURL;

  useEffect(() => {
    if (!loading) {
      /**
       * The second file upload, loading is false, but
       * uploadURL is the same as the first upload. After
       * this happens, the data is updated with the new
       * URL, but it is after the effect is triggered.
       * The effect is not triggered again.
       */
      if (uploadURL && blob && successCb && failureCb) {
        uploadFile(uploadURL, blob, successCb, failureCb);
      }
    }
  }, [uploadURL, blob, success, failureCb, loadingCb]);

  return (
    <div>
      <Editor
        uploadHandler={uploadHandler}
      />
    </div>
  );
}

The result was that the old URL was used for the second upload (since loading was false), and shortly after (by looking at the output of console.log right after the useLazyQuery hook), the data was updated. The expectation was that the new URL would be present when loading was false in the useEffect.

Version

npx: installed 1 in 1.291s
  System:
    OS: Linux 4.15 Ubuntu 18.04.4 LTS (Bionic Beaver)
  Binaries:
    Node: 10.18.0 - ~/.asdf/installs/nodejs/10.18.0/bin/node
    Yarn: 1.22.4 - /usr/bin/yarn
    npm: 6.13.4 - ~/.asdf/installs/nodejs/10.18.0/bin/npm
  Browsers:
    Chrome: 81.0.4044.138
    Firefox: 76.0.1
  npmPackages:
    @apollo/react-hooks: ^3.1.3 => 3.1.3 
    @apollo/react-testing: ^3.1.3 => 3.1.3 
    apollo-cache-inmemory: ^1.6.5 => 1.6.5 
    apollo-client: ^2.6.8 => 2.6.8 
    apollo-link: ^1.2.13 => 1.2.13 
    apollo-link-http: ^1.5.16 => 1.5.16 
    apollo-link-state: ^0.4.0 => 0.4.2 
    react-apollo: ^3.1.3 => 2.5.8 

kylehovey avatar May 20 '20 18:05 kylehovey