Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Load more scenario #104

Open
roboticflamingo opened this issue Apr 1, 2022 · 3 comments
Open

Load more scenario #104

roboticflamingo opened this issue Apr 1, 2022 · 3 comments

Comments

@roboticflamingo
Copy link

I was using this library in a load more scenario (infinity scolling) - there does not seem to be a way to stop suspense being triggered causing a redraw when the getter is used to pull the next set of data - for example, when you want to add items to an array of rows in state.

If the library can handle this, some documentation for this specific scenario would be great or perhaps a modification to allow disabling of the suspense feature.

Currently the library works well for the initial load, but not for the load more deltas :)

@Rowansdabomb
Copy link

I came here to request the same thing.

There are many situations when it is favourable for a component to keep showing a "stale" value while making subsequent api requests. I think both the "show stale values on update" and the current "show fallback on update" behaviours are needed depending on the situation.

Looking through your code I notice the use of rest parameters for grabbing the async function arguments, so I'm not sure what would be the best way of specifying this option without changing the current argument structure for useAsyncResource.

First thought that comes to mind is optionally specifying an options object as the last parameter, with the obvious repercussions of inhibiting the async function from accepting an argument that matches the Options object.

// This code is untested
const OPTIONS_OWN_NAMES = new Set(["showStaleOnUpdate"]);
const DEFAULT_OPTIONS = {showStaleOnUpdate: false};

const optionsFromParameters = (parameters) => {
  const last = parameters?.[parameters.length-1];
  if (last == null) return DEFAULT_OPTIONS;

  const ownNames = Object.getOwnPropertyNames(last);
  if (ownNames.length === 0) return DEFAULT_OPTIONS;

  const isOptionsParameter = ownNames.reduce((acc, name) => acc && OPTIONS_OWN_NAMES.has(name), true);
  if (!isOptionsParameter) return DEFAULT_OPTIONS

  parameters.pop();
  return {...DEFAULT_OPTIONS, ...last};
}

export function useAsyncResource(apiFunction, ...parameters) {
  const options = optionsFromParameters(parameters);
}

// called like this to specify options
useAsyncResource(asyncFunc, 1, 2, 3, {showStaleOnUpdate: true}) // but what if my asyncFunc needs an argument that matches {showStaleOnUpdate: true} :(

// still works as normal without options
useAsyncResource(asyncFunc, 1, 2, 3)

@FezVrasta
Copy link

FezVrasta commented Jun 8, 2023

Same problem but for "pull to refresh", users want to keep seeing the stale data as the new one is fetched.

I think a possible solution would be to have a way to mark some cache as stale, so that rather than deleting it and refetching, you can mark it as stale and refetch it.

@FezVrasta
Copy link

I realized we can use React.startTransition to avoid the loading indicator.

https://stackblitz.com/edit/stackblitz-starters-svgxwt?file=src%2FApp.tsx

import * as React from 'react';
import { useAsyncResource } from 'use-async-resource';

async function fetchUser(id: number) {
  await new Promise((resolve) => {
    setTimeout(() => resolve(void 0), 2000);
  });

  return { name: `name ${id}` };
}

export function App() {
  const [userReader, getNewUser] = useAsyncResource(fetchUser, 1);

  return (
    <>
      <React.Suspense fallback="user is loading...">
        <User userReader={userReader} />
      </React.Suspense>

      <br />

      <button
        onClick={() =>
          React.startTransition(() => {
            getNewUser(2);
          })
        }
      >
        Get user with id 2 with no loading indicator
      </button>

      <button onClick={() => getNewUser(2)}>
        Get user with id 2 with loading indicator
      </button>
    </>
  );
}

function User({ userReader }) {
  const userData = userReader();

  return <div>{userData.name}</div>;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants