Use a resource to fetch the data outside the Home
component. If you need to fetch the data once during application's life, cache it.
https://www.solidjs.com/docs/latest/api#createresource
Lets make it more clear. There are different patterns to render async data, data that resides in a remote location.
- Fetch as you render: In this pattern, data is fetched when the component mounts.
ComponentA
below uses this pattern. Whenever it is re-rendered, data will be re-fetched.
- Fetch then render: In this pattern, data is fetched outside the component, in one of its parent's scope. When component mounts it can use whatever is currently available, by whatever, I mean the request may not be resolved yet so state will be pending.
Resource API is build to make use of this pattern.
ComponentB
below uses this pattern. Since data is fetched outside the component, re-rendering has no effect on it.
import { Accessor, Component, createSignal, Match, Switch } from 'solid-js';
import { render } from 'solid-js/web';
interface State { status: 'pending' | 'resolved' | 'rejected', data?: any, error?: any };
function getData(): Accessor<State> {
const [state, setState] = createSignal<State>({ status: 'pending' });
setTimeout(() => {
setState({ status: 'resolved', data: { name: 'John Doe', age: 30 } });
}, 1000);
return state;
};
const ComponentA = () => {
const state = getData();
return (
<Switch fallback={<div>Not Found</div>}>
<Match when={state().status === 'pending'}>
Loading...
</Match>
<Match when={state().status === 'resolved'}>
{JSON.stringify(state().data)}
</Match>
<Match when={state().status === 'rejected'}>
{JSON.stringify(state().error)}
</Match>
</Switch>
);
};
const ComponentB: Component<{ state: Accessor<State> }> = (props) => {
return (
<Switch fallback={<div>Not Found</div>}>
<Match when={props.state().status === 'pending'}>
Loading...
</Match>
<Match when={props.state().status === 'resolved'}>
{JSON.stringify(props.state().data)}
</Match>
<Match when={props.state().status === 'rejected'}>
{JSON.stringify(props.state().error)}
</Match>
</Switch>
);
};
const App = () => {
const state = getData();
const [show, setShow] = createSignal(false);
const handleClick = () => setShow(prev => !prev);
return (
<div>
{show() && (<ComponentA />)}
{show() && (<ComponentB state={state} />)}
<div><button onclick={handleClick}>Toggle Show Components</button></div>
</div>
)
};
render(() => <App />, document.body);
Here you can see it in action: https://playground.solidjs.com/anonymous/32518df5-9840-48ea-bc03-87f26fecc0f4
Here we simulated an async request using setTimeout. This is very crude implementation to prove a point. If you are going to fetch a remote resource, you should use the Resource API which provides several utilities like automatic re-fecthing when request parameters change.
There are few issues with your implementation. First and foremost, async data in never guaranteed to be received, so you should handle failures.
Since it takes some time to receive the remote data, you have to show the user some indicator of the ongoing request, like a loader.
If API call is an expensive operation, you have to cache the result, rather than forcing the UI not to re-render. In this sense, your approach is very problematic.