Skip to content

Commit

Permalink
feat: replace rerenderInAction to: renderPage and `renderComponen…
Browse files Browse the repository at this point in the history
…t` (#682)

* docs: add new renderPage and renderComponent docs

* feat: add renderPage and renderComponent

* feat: adapt resolveAction to the new methods

* fix: fix resolve rpc

* test: fix test

* feat: add warn to rerenderInAction

* fix: fix types

* feat: render element

* feat: add target

* feat: add target

* feat: use target

* feat: support append, prepend, before and after

* fix: tests

* reformat

* chore: clean

* fix: replace rerenderInAction

* refactor
  • Loading branch information
aralroca authored Dec 15, 2024
1 parent 930ef98 commit 6624905
Show file tree
Hide file tree
Showing 39 changed files with 1,599 additions and 561 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,6 @@ tsconfig.tsbuildinfo
## Panda
styled-system
styled-system-studio

## Deno (we are using bun.lockb)
deno.lock
Binary file modified bun.lockb
Binary file not shown.
4 changes: 2 additions & 2 deletions docs/api-reference/functions/throwable.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ description: Determines if an object is an instance of the Throwable class.
`throwable` is an object that contains methods to check if an error is an internal Brisa trowable. It is used to handle specific scenarios such as re-rendering, navigation, and not-found errors.

- **throwable.is**: checks **all** throwable types.
- **throwable.isRerender** checks if an error is a re-render throwable (from [`rerenderInAction`](/api-reference/server-apis/rerenderInAction) API).
- **throwable.isRerender** checks if an error is a re-render throwable (from [`renderPage`](/api-reference/server-apis/renderPage) and [`renderComponent`](/api-reference/server-apis/renderComponent) API).
- **throwable.isNavigate** checks if an error is a navigate throwable (from [`navigate`](/api-reference/functions/navigate) API).
- **throwable.isNotFound** checks if an error is a not-found throwable (from [`notFound`](/api-reference/functions/notFound) API).

Expand Down Expand Up @@ -119,4 +119,4 @@ interface Throwable {
}

export const throwable: Throwable;
```
```
3 changes: 2 additions & 1 deletion docs/api-reference/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ The Brisa API reference is divided into the following sections:

## Server APIs

- [`renderInAction`](/api-reference/server-apis/rerenderInAction)
- [`renderPage`](/api-reference/server-apis/renderPage)
- [`renderComponent`](/api-reference/server-apis/renderComponent)
- [`renderToReadableStream`](/api-reference/server-apis/renderToReadableStream)
- [`renderToString`](/api-reference/server-apis/renderToString)
- [`getServeOptions`](/api-reference/server-apis/getServeOptions)
Expand Down
88 changes: 88 additions & 0 deletions docs/api-reference/server-apis/renderComponent.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
---
description: rerender the component inside a server action
---

# renderComponent

## Reference

### `renderComponent({ element, target, mode, withTransition }: RenderComponentProps): Never`

The `renderComponent` method is used to rerender the component or render some component in an specific target location inside a server action. Outside of an action, it throws an error.

`renderComponent` needs to be called outside of the `try/catch` block:

```tsx
export default function MyComponent({ text = "foo" }: { text: string }) {
function handleClick() {
// Just a component rerender:
renderComponent();

// Trigger a component rerender with new props
renderComponent({ element: <MyComponent text="bar" />});

// Render a specific component on target location
renderComponent({
element: <Component {...props} />,
target: "#target-id",
mode: "replace",
withTransition: true,
});
}

return (
<div>
<button onClick={handleClick}>{text}</button>
</div>
);
}
```

> [!NOTE]
>
> See the differences between "Action Signals" and `renderComponent` in [this documentation](/building-your-application/data-management/server-actions#action-signals-vs-rerender).
#### Types:

```ts
function renderComponent<PropsType>(
props: RenderComponentProps<PropsType> = {},
): never;

type RenderComponentProps = {
element?: JSX.Element;
target?: string;
placement?: 'replace' | 'before' | 'after' | 'append' | 'prepend';
withTransition?: boolean;
};
```

#### Parameters:

- `element` (optional): The component to render. By default, it will rerender the target component that triggered the action.
- `target` (optional): The target location to render the component. It can be a CSS selector.
- `placement` (optional): The placement to render the component. It can be `replace`, `before`, `after`, `append` or `prepend`. Default is `replace`.
- `withTransition` (optional): If `true`, it will render the component with [start view transition API](https://developer.mozilla.org/en-US/docs/Web/API/Document/startViewTransition). Default is `false`.

#### Returns:

- `Never` does not require you to use `return renderComponent()` due to using the TypeScript [`never`](https://www.typescriptlang.org/docs/handbook/2/functions.html#never) type.

> [!CAUTION]
>
> Avoid using the `renderComponent` inside a `try/catch` block. The `navigate` is a throwable function and will break the execution of the current function.
> [!TIP]
>
> Updating [`Action Signals`](/building-your-application/data-management/server-actions#action-signals) by default is going to use a `renderComponent` without you having to specify it. If you specify it, it will fulfill only the `renderComponent` you specify.
### Support

| Component | Support |
| ----------------- | ------- |
| Server Component ||
| Web Component ||
| SSR Web Component ||
| Actions ||
| Middleware ||
| Response headers ||
63 changes: 63 additions & 0 deletions docs/api-reference/server-apis/renderPage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
---
description: rerender the page inside a server action
---

# renderPage

## Reference

### `renderPage(): Never`

The `renderPage` method is used to rerender the page inside a server action. Outside of an action, it throws an error.

`renderPage` needs to be called outside of the `try/catch` block:

```tsx
import { renderPage } from "brisa/server";

// Inside a server action
function handleEvent() {
try {
// ...
} catch (error) {
// ...
}

// Trigger a full-page rerender
renderPage();
}
```

> [!NOTE]
>
> See the differences between "Action Signals" and `renderPage` in [this documentation](/building-your-application/data-management/server-actions#action-signals-vs-rerender).
### Parameters

- `withTransition` (optional): A boolean value that indicates whether the rerender should be done with [start view transition](https://developer.mozilla.org/en-US/docs/Web/API/Document/startViewTransition). Default is `false`.


#### Types:

```ts
function renderPage(): never;
```

#### Returns:

- `Never` does not require you to use `return rerenderInPage()` due to using the TypeScript [`never`](https://www.typescriptlang.org/docs/handbook/2/functions.html#never) type.

> [!CAUTION]
>
> Avoid using the `renderPage` inside a `try/catch` block. The `navigate` is a throwable function and will break the execution of the current function.
### Support

| Component | Support |
| ----------------- | ------- |
| Server Component ||
| Web Component ||
| SSR Web Component ||
| Actions ||
| Middleware ||
| Response headers ||
99 changes: 0 additions & 99 deletions docs/api-reference/server-apis/rerenderInAction.md

This file was deleted.

10 changes: 5 additions & 5 deletions docs/building-your-application/authentication/authentication.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ Consider a server component with login form where users can input their credenti

```tsx 9-10
import { navigate, type RequestContext } from "brisa";
import { rerenderInAction } from "brisa/server";
import { renderPage } from "brisa/server";
import signIn from "@/utils/auth/sign-in";

export default function LoginPage({}, request: RequestContext) {
Expand All @@ -40,7 +40,7 @@ export default function LoginPage({}, request: RequestContext) {
if (success) navigate("/admin");

request.store.set("auth-error", "Invalid credentials");
rerenderInAction({ type: "page" });
renderPage();
}

return (
Expand All @@ -66,15 +66,15 @@ After the authentication provider processes the credentials, there are two possi
- **Successful Authentication**: This outcome implies that the login was successful. Further actions, such as accessing protected routes and fetching user information, can then be initiated.
- **Failed Authentication**: In cases where the credentials are incorrect or an error is encountered, the function returns a corresponding error message to indicate the authentication failure.

Finally, you can `navigate` to another page or use the request `store` to save form errors, and use `rerenderInAction` to render these errors on the form:
Finally, you can `navigate` to another page or use the request `store` to save form errors, and use `renderPage` to render these errors on the form:

```tsx
if (success) navigate("/admin");

request.store.set("auth-error", "Invalid credentials");
rerenderInAction({ type: "page" });
renderPage();
```

> [!IMPORTANT]
>
> Both `navigate` and `rerenderInAction` throw an exception returning a [Never](https://www.typescriptlang.org/docs/handbook/basic-types.html#never) type, therefore the code after is not executed so there is no need to put an `else` conditional. It is important to keep this in mind because if it is put in a `try-catch` they would stop working unless from the catch you throw again these actions.
> Both `navigate` and `renderPage` throw an exception returning a [Never](https://www.typescriptlang.org/docs/handbook/basic-types.html#never) type, therefore the code after is not executed so there is no need to put an `else` conditional. It is important to keep this in mind because if it is put in a `try-catch` they would stop working unless from the catch you throw again these actions.
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ No directly. The signals are reactive and they are used in the client-side. Howe

```tsx
import type { RequestContext } from "brisa";
import { rerenderInAction } from "brisa/server";
import { renderPage } from "brisa/server";

export default function ServerComponent({}, { store }: RequestContext) {
// Setting store
Expand All @@ -204,7 +204,7 @@ export default function ServerComponent({}, { store }: RequestContext) {
function updateName() {
// Update the store inside a server action
store.set("user", { username: "bar", displayName: "Bar" });
rerenderInAction({ type: "page" });
renderPage();
}

// Consuming store
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ export default function UserImages({ urls = [], width = 300, height = 300 }) {

### `key` property

Each child in a list should have a unique "`key`" prop. Keys tell Brisa which array item each component corresponds to, so that it can match them up later after the execution of a [`server action`](/building-your-application/data-management/server-actions) that does a [`rerenderInAction`](/api-reference/server-apis/rerenderInAction). This becomes important if your array items can move (e.g. due to sorting), get inserted, or get deleted. A well-chosen key helps Brisa infer what exactly has happened, and make the correct updates to the DOM tree after the server action execution.
Each child in a list should have a unique "`key`" prop. Keys tell Brisa which array item each component corresponds to, so that it can match them up later after the execution of a [`server action`](/building-your-application/data-management/server-actions) that does a [`renderPage`](/api-reference/server-apis/renderPage) or [`renderComponent`](/api-reference/server-apis/renderComponent). This becomes important if your array items can move (e.g. due to sorting), get inserted, or get deleted. A well-chosen key helps Brisa infer what exactly has happened, and make the correct updates to the DOM tree after the server action execution.

```tsx
export default function List({ people }) {
Expand Down Expand Up @@ -247,7 +247,7 @@ The `store` is a **shared** state among all server-components (possible to trans

```tsx
import type { RequestContext } from "brisa";
import { rerenderInAction } from "brisa/server";
import { renderPage } from "brisa/server";

export default function SharedStore({}, { store }: RequestContext) {
// Setting store
Expand All @@ -262,7 +262,7 @@ export default function SharedStore({}, { store }: RequestContext) {
function updateName() {
// Update the store inside a server action
store.set("user", { username: "bar", displayName: "Bar" });
rerenderInAction({ type: "page" });
renderPage();
}

// Consuming store
Expand Down
Loading

0 comments on commit 6624905

Please sign in to comment.