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

Async State not re-rendering when promise immediately resolved #186

Closed
from-nibly opened this issue Jun 3, 2021 · 2 comments
Closed

Async State not re-rendering when promise immediately resolved #186

from-nibly opened this issue Jun 3, 2021 · 2 comments
Labels
bug Something isn't working

Comments

@from-nibly
Copy link

I have a utility component that transitions between states when waiting for async functions to resolve.

It looks like this

interface StateProps<T extends State<any>[]> {
  state: [...T];
  children: {
    whileLoading: () => ReactElement;
    whileResolved: (...args: T) => ReactElement;
    whileRejected: (...errors: any) => ReactElement;
  };
}

export const AsyncStateLoader = <T extends State<any>[]>({
  children,
  state,
}: StateProps<T>) => {
  const resolved = state.filter((s) => !s.promised);
  console.log(
    'rendering',
    state.map((s) => s.promised)
  );

  if (resolved.length !== state.length) {
    return children.whileLoading();
  }

  const errored = state.filter((s) => s.error);

  if (errored.length > 0) {
    return children.whileRejected(errored.map((e) => e.error));
  }

  return children.whileResolved(...state);
};

I've found a couple issues using this.

  1. Using an async function with no parameters the function never gets called
const MyComponent: FC<{}> = () => {
  const myState = useState(createState);

  return (
    <AsyncStateLoader state={[myState]}>
      {{
        whileLoading: () => <div>Loading</div>,
        whileResolved: (myState) =>  <h1>myState</h1>,
        whileRejected: (errors) => <div> Error{JSON.stringify(errors)}</div>,
      }}
    </AsyncStateLoader>
  );
}

const createState = async () => {
  return 'foo'
}

Wrapping with an anonymous function fixes this.

const MyComponent: FC<{}> = () => {
  const myState = useState(() => createState());
}

const createState = async () => {
  return 'foo'
}

However, now it only renders the AsyncStateLoader component once.

Which means it only outputs the following, stating that it is still waiting for the promise to be resolved.

rendering [true]

If I change the createState function to run in another tick it fixes it.

const createState = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('foo');
    }, 0);
  });
}
@avkonst
Copy link
Owner

avkonst commented Jun 4, 2021

Thanks for the report. I will check it out. I think it is the same as this one: #165
but now I should have a solid reproducer for for this. You can also try the fix proposed for the #165 and see if it solves this problem. If it solves, please feel free to submit a PR with the fix and your case put in as a unit test.

@avkonst avkonst added the bug Something isn't working label Jun 4, 2021
avkonst added a commit that referenced this issue Jun 8, 2021
avkonst added a commit that referenced this issue Jun 8, 2021
@avkonst
Copy link
Owner

avkonst commented Jun 8, 2021

Very likely fixed in 3.0.8. Please verify, I could not reproduce it unit tests. If it does not fix it, please reopen the ticket. Thanks

@avkonst avkonst closed this as completed Jun 8, 2021
shinyjohn0401 pushed a commit to shinyjohn0401/hookstate that referenced this issue Jan 22, 2024
shinyjohn0401 pushed a commit to shinyjohn0401/hookstate that referenced this issue Jan 22, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants