Skip to content

Commit

Permalink
Merge pull request #106 from mittwald/rename-watch-to-use
Browse files Browse the repository at this point in the history
Use "use" instead of "watch" for more naming consistency
  • Loading branch information
mfal authored Nov 7, 2023
2 parents d1d85d2 + 54bb1f0 commit 50f3fde
Show file tree
Hide file tree
Showing 8 changed files with 39 additions and 31 deletions.
2 changes: 1 addition & 1 deletion .pnp.cjs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

50 changes: 25 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ details see
[Lazy Loading with Async Resources](#-lazy-loading-with-async-resources). The
`usePromise` hook uses the [`getAsyncResource`-API](#getasyncresource) under the
hood and is basically just a shortcut for
`getAsyncResource(asyncLoader, loaderParameters, options).watch()`.
`getAsyncResource(asyncLoader, loaderParameters, options).use()`.

Get an async resource by passing an async loader with the relevant loader
parameters and an optional configuration to the `getAsyncResource` function.
Expand Down Expand Up @@ -195,35 +195,35 @@ const getUserResource = (id) => getAsyncResource(getUser, [id]);

The async resource returned by `getAsyncResource` has the following API.

#### .watch()
#### .use()

Returns: the value of the async resource, or the result object when
`useSuspense: false` (see [Opt-out Suspense](#opt-out-suspense))

Calling the `watch` method will actually start the loading process and returns
the value of the async resource, once it is loaded. Everytime the resource is
refreshed, the watched value automatically updates itself.
Calling the `use` method will actually start the loading process and returns the
value of the async resource, once it is loaded. Everytime the resource is
refreshed, the used value automatically updates itself.

```jsx
import getUserResource from "../resources/user";

const Username = ({ id }) => {
const user = getUserResource(id).watch(); // 👈 watching the resource value
const user = getUserResource(id).use(); // 👈 using the resource value
return <>{user.name}</>;
};
```

#### .refresh()

Calling the `refresh` method will clear the cached resource value and trigger a
reload, if the resource is being watched in any mounted component.
reload, if the resource is being used in any mounted component.

```jsx
import getScoreResource from "../resources/score";

const Score = ({ matchId }) => {
const scoreResource = getScoreResource(matchId);
const score = scoreResource.watch();
const score = scoreResource.use();
const reloadScore = () => scoreResource.refresh(); // 👈 refresh the resource

return (
Expand All @@ -249,7 +249,7 @@ import getScoreResource from "../resources/score";
const Score = ({ matchId }) => {
const scoreResource = getScoreResource(matchId);
const scoreResourceState = scoreResource.watchState();
const score = scoreResource.watch();
const score = scoreResource.use();
const scoreIsLoading = scoreResourceState === "loading";

return (
Expand Down Expand Up @@ -381,7 +381,7 @@ const getUser = (id) => axios(`/user/${id}`);
const getUserResource = resourceify(getUser);
// `myUser` is an async resource
const myUser = getUserResource(["me"], { refresh: { seconds: 30 } });
myUser.watch();
myUser.use();

// Factory method for HTTP GET-Requests via Axios
import axios from "axios";
Expand Down Expand Up @@ -684,8 +684,8 @@ For instance if user profiles can be loaded via multiple API methods, the
`<UserAvatar />` component can still be used without any changes.

It is noticeable that creating Async Resources in any parent component does
**not trigger the loading process**. Therefore, the `.watch()` method can be
used in the child components, where the data is actually needed.
**not trigger the loading process**. Therefore, the `.use()` method can be used
in the child components, where the data is actually needed.

Alternative Container Component with lazy loading:

Expand All @@ -700,8 +700,8 @@ interface Props {
}

const UserAvatar: FC<Props> = ({ user, size }) => {
// .watch() 🔔 triggers loading when needed
const profile = user.watch();
// .use() 🔔 triggers loading when needed
const profile = user.use();
return <Avatar imageUrl={profile.avatarUrl} size={size} />;
};

Expand Down Expand Up @@ -756,20 +756,20 @@ const App = () => (

### Gotchas when defining "built-in" loading views

When you are using `.watch()` or `usePromise()` in your component, it can not
When you are using `.use()` or `usePromise()` in your component, it can not
define its own loading boundary - at least not for directly used Async
Resources.

In this example the fallback component will not be shown:

```jsx
const UserAvatar = ({ userResource, size }) => {
const user = userResource.watch();
const user = userResource.use();
// 👆 any code below this line will not be executed 🙅 until the async loader is done.
const loadingView = <AvatarSkeleton size={size} />;
return (
<Suspense fallback={loadingView}>
{/* This fallback 👆 is not rendered for the watched resource from above. 😢 */}
{/* This fallback 👆 is not rendered for the used resource from above. 😢 */}
<Avatar imageUrl={user.avatarUrl} size={size} />
</Suspense>
);
Expand All @@ -784,7 +784,7 @@ The following approaches can help you to solve this issue:

```jsx
const Component = ({ userResource, size }) => {
const user = userResource.watch();
const user = userResource.use();
return <Avatar imageUrl={user.avatarUrl} size={size} />;
};

Expand All @@ -803,7 +803,7 @@ export const UserAvatar = (props) => {

```jsx
const UserAvatar = ({ userResource, size }) => {
const user = userResource.watch({ useSuspense: false });
const user = userResource.use({ useSuspense: false });

// `user` is an object with `isSet` and `value` properties
if (!user.isSet) {
Expand All @@ -820,7 +820,7 @@ const UserAvatar = ({ userResource, size }) => {

```jsx
const UserAvatar = withLoadingBoundary(({ userResource, size }) => {
const user = userResource.watch();
const user = userResource.use();
return <Avatar imageUrl={user.avatarUrl} size={size} />;
}, AvatarSkeleton);
```
Expand All @@ -834,7 +834,7 @@ const UserAvatar = ({ userResource, size }) => {
<Suspense fallback={loadingView}>
<Render>
{() => {
const user = userResource.watch();
const user = userResource.use();
return <Avatar imageUrl={user.avatarUrl} size={size} />;
}}
</Render>
Expand All @@ -851,8 +851,8 @@ components with
[built-in loading views](#gotchas-when-defining-built-in-loading-views).

You can opt-out Suspense by setting the `useSuspense` option to `false`. When
Suspense is disabled, calling `.watch()` resp. `usePromise()` will not trigger
any `<Suspense />` component. Instead, a result object is returned, containing
Suspense is disabled, calling `.use()` resp. `usePromise()` will not trigger any
`<Suspense />` component. Instead, a result object is returned, containing
loading information and the eventual value.

Example of how the opt-out behaves:
Expand All @@ -871,7 +871,7 @@ return (

### Return object with disabled Suspense

The object returned by `.watch()` resp. `usePromise()` has the following
The object returned by `.use()` resp. `usePromise()` has the following
properties, when Suspense is disabled.

- `isLoading`: Is `true` when the resource is loading or reloading. `false`
Expand Down Expand Up @@ -1015,7 +1015,7 @@ export class UserProfile {
}

public static useLoadById(id: string): UserProfile {
const data = getUserProfile([id]).watch();
const data = getUserProfile([id]).use();
return new UserProfile(data);
}

Expand Down
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -97,5 +97,10 @@
"email": "[email protected]"
}
],
"dependenciesMeta": {
"[email protected]": {
"unplugged": true
}
},
"packageManager": "[email protected]"
}
2 changes: 1 addition & 1 deletion src/resource/AsyncResource.test-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ interface ResultType {
function testResultOfWatchMatchesAsyncLoaderReturnType() {
const resource = {} as AsyncResource<ResultType>;

const result = resource.watch();
const result = resource.use();
expectType<ResultType>(result);

// @ts-expect-error Test access to unknown props
Expand Down
2 changes: 1 addition & 1 deletion src/resource/AsyncResource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ export class AsyncResource<T = unknown> {
this.autoRefreshTimeout.start();
}

public watch<TOptions extends UseWatchResourceOptions>(
public use<TOptions extends UseWatchResourceOptions>(
options: TOptions = {} as TOptions,
): UseWatchResourceResult<T, TOptions> {
return useWatchResourceValue(this, options);
Expand Down
4 changes: 2 additions & 2 deletions src/resource/getAsyncResource.test-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,12 @@ function testGetAsyncResourceRequiresCorrectParameters() {

// eslint-disable-next-line @typescript-eslint/no-unused-vars
function testWatchedResultIsLoaderReturnType() {
const value = getAsyncResource(loader, [true, "foo"]).watch();
const value = getAsyncResource(loader, [true, "foo"]).use();
expectType<number>(value);
}

// eslint-disable-next-line @typescript-eslint/no-unused-vars
function testWatchedResultIncludesUndefinedWhenParametersIsNull() {
const optionalValue = getAsyncResource(loader, null).watch();
const optionalValue = getAsyncResource(loader, null).use();
expectType<number | undefined>(optionalValue);
}
2 changes: 1 addition & 1 deletion src/use-promise/usePromise.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,5 @@ export function usePromise<
parameters: TParams | null,
options: TOptions = {} as TOptions,
): UseWatchResourceResult<TValue | undefined, TOptions> {
return getAsyncResource(asyncLoader, parameters, options).watch(options);
return getAsyncResource(asyncLoader, parameters, options).use(options);
}
3 changes: 3 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1014,6 +1014,9 @@ __metadata:
typescript: "npm:~5.2.2"
peerDependencies:
react: ">=17.0"
dependenciesMeta:
[email protected]:
unplugged: true
languageName: unknown
linkType: soft

Expand Down

0 comments on commit 50f3fde

Please sign in to comment.