Question regarding behavior of generator based components #84
-
@brainkim (or who else likes to help) One of the killer features of Crank is something like the following (this async function* Loader() {
for await (const { loadingText = 'Loading...', finishText = 'Finished!' } of this) {
yield <div>{loadingText}</div>
await wait(4000)
yield <div>{finishText}</div>
}
} The problem is that by the nature of the concept this Please find below two demos (I hope the demos are self-explaining). React: Crank: Does really nobody have a problem with this component behavior in Crank? |
Beta Was this translation helpful? Give feedback.
Replies: 4 comments 13 replies
-
If you change the loader component in the Crank example to the following then it will behave like the React example. async function* Loader() {
let rendered = false;
for await (const { loadingText = 'Loading...', finishText = 'Finished!' } of this) {
yield <div>{loadingText}</div>
if (!rendered) await wait(4000)
yield <div>{finishText}</div>
rendered = true;
}
} The reason for this, in the React example the usePromise hook runs only on the first render as it has a dependency array, so when the component refreshes, it doesn't run the promise again so it doesn't set the loading text again. But in the Crank example the promise is executed each time, so in the above code the promise is only executed on the first render. |
Beta Was this translation helpful? Give feedback.
-
Thanks @lazeebee @brainkim This is a good example of why I sometimes tend to criticizes a bit that currently most Crank examples do not really cover real world patterns. In the real world - at least in non-trivial applications - there's a good chance that a lot of your components have multiple props, are localizable and themeable (let's say using a css-in-js solution) and have side-effects that depend on some prop values. So this simple
pattern will actually in many cases not really work in this simplicity. Thanks a lot to everybody ... will close this issue now... |
Beta Was this translation helpful? Give feedback.
-
Sorry I didn’t get to respond before it closed. One thing you could do is keep track of promises in the async generator component, and only kick off an async request if props require it. So you could do something like: async function *Loader(props) {
let fetchResult;
for await (const newProps of this) {
if (fetchResult == null || needsFetch(props, newProps)) {
yield <div>Loading...</div>;
fetchResult = await myFetchAPI(newProps);
props = newProps;
}
yield <Result>{fetchResult.toString()</Result>;
}
} Essentially, with generators you get useMemo for free! |
Beta Was this translation helpful? Give feedback.
-
I’ve also signed up the repository for GitHub discussions so if you’d like to ask questions without worrying about when to close the issue you can hit up the discussions tab! |
Beta Was this translation helpful? Give feedback.
If you change the loader component in the Crank example to the following then it will behave like the React example.
The reason for this, in the React example the usePromise hook runs only on the first render as it has a dependency array, so when the component refreshes, it doesn't run the promise again so it doesn't set the loading text again. But in the Crank example the promise is executed each time, so in the above cod…