diff --git a/articles/building-apps/views/add-view/hilla.adoc b/articles/building-apps/views/add-view/hilla.adoc index dd03083442..bda95c9fc9 100644 --- a/articles/building-apps/views/add-view/hilla.adoc +++ b/articles/building-apps/views/add-view/hilla.adoc @@ -64,6 +64,8 @@ Defining the function name as `customersView` or `customerList` does not result The routing uses the React component's name for creating the default automatic title for the view. For example, the title for the `CustomersView` component is `Customers`, and the title for the `HelloWorldView` component is `Hello World`. This automatically-determined title is used when creating the navigation menu based on utilities from the routing API. +Another important convention to consider while naming the views and directories is to use the `_` (underscore) character at the beginning of the file or directory name to instruct the routing system to ignore it. For example, a file named as `_AddressFormComponent.tsx` is ignored when creating routes for views. This is useful for creating utility files and reusable components that are not intended to be available as navigation targets. + The details about the automatic title and the navigation menu are covered in more detail in the <<../navigate#,Navigate to a View>> guide. diff --git a/articles/building-apps/views/navigate/hilla.adoc b/articles/building-apps/views/navigate/hilla.adoc new file mode 100644 index 0000000000..7dcf4cb440 --- /dev/null +++ b/articles/building-apps/views/navigate/hilla.adoc @@ -0,0 +1,181 @@ +--- +title: React +page-title: How to navigate to a view in React | Vaadin +description: Learn how to navigate between React views in a Vaadin application. +meta-description: This guide covers how to navigate to a React or Flow view in Vaadin applications, including creating links and programmatic navigation. +order: 10 +--- + + += Navigation in React + +In this guide, you'll learn how to use `` component and `useNavigate` hook of `react-router` to navigate between views. At the end, a mini-tutorial helps you to apply these concepts in a real Vaadin application. + + +== Navigating Between Views Using Links + +The `` component from `react-router` renders a clickable link for navigation. In HTML, it corresponds to an anchor (``) element. + +[TIP] +Links are preferable to programmatic navigation because they *improve accessibility*. They also allow users to open links in new browser tabs. + + +For example, to create a link to a view located at `/some-view`, you can use the following code: + +[source,tsx] +---- +import { NavLink } from 'react-router'; + +Some View +---- + +This code creates a clickable link labeled "Some View" that navigates to the `/some-view` route when clicked. + + +== Programmatic Navigation + +In some scenarios, you may need to navigate between views programmatically, such as after a form submission or in response to user interactions. For this you can use the `useNavigate` hook of `react-router` to achieve this. + +Here's an example of how to use `useNavigate` for programmatic navigation: + +[source,tsx] +---- +import { useNavigate } from 'react-router'; + +function MyComponent() { +const navigate = useNavigate(); + + const handleClick = () => { + navigate('/target-view'); + }; + + return ( + + ); +} +---- + +In the above example, clicking the button navigates the user to `/target-view`. + + +== Flow Views + +To navigate from a React view to a Flow view that is implemented in Java, the same principles apply. You can use the `NavLink` component or the `useNavigate` hook to navigate to the Flow view. + + +== Try It + +In this mini-tutorial, you'll learn how to navigate between React views using both *links* and *programmatic navigation*. + + +First, generate a <<{articles}/getting-started/start#,walking skeleton with a React UI>>, <<{articles}/getting-started/import#,open>> it in your IDE, and <<{articles}/getting-started/run#,run>> it. + + +=== Modify the Todo View + +Change the path of the `TodoView` to `todo`. The `TodoView` is stored in the file `@index.tsx` that is located directly under the `views` directory. To change its route to `/todo`, rename the file to `todo.tsx` so that the directory structure looks like this: + +[source] +---- +views +├── @layout.tsx +├── _ErrorHandler.ts +└── todo.tsx +---- + +This is a convenience step for having a simple and clear Main view for the next steps. + + +=== Create the About View + +You'll start by creating a new view called `AboutView`. This view is going to be the target view of navigation in this mini-tutorial. In the `views` directory, create a new file named [filename]`about.tsx`: + +[source,tsx] +.about.tsx +---- +export default function AboutView() { + return

About View

; +} +---- + +The path for this view is automatically resolved to `/about`, and users can access it by navigating to `\https://example.com/about`. + +=== Create a Main View + +Next, create a new main view. This view is going to be the source of navigation in this mini-tutorial. In the `views` directory, create a new file called `@index.tsx`: + +[source,tsx] +.@index.tsx +---- +export default function MainView() { + return

Main View

; +} +---- + +=== Add a Link to the Main View + +Now, add a link that targets the `AboutView` from the `MainView`. In the `@index.tsx` file, add the following code: + +[source,tsx] +.@index.tsx +---- +import { NavLink } from 'react-router'; + +export default function MainView() { + return ( + <> +

Main View

+ Link to About + + ); +} +---- + +This code creates a clickable link labeled "Link to About" that navigates to the `/about` route when clicked. + +=== Add a Button for Programmatic Navigation + +Now, add a button that navigates to the `AboutView` programmatically. In the `@index.tsx` file, change the codes to have the following code: + +[source,tsx] +.@index.tsx +---- +import { NavLink, useNavigate } from 'react-router'; + +export default function MainView() { + const navigate = useNavigate(); + + const handleClick = () => { + navigate('/about'); + }; + + return ( + <> +

Main View

+ Link to About + + + ); +} +---- + +This code creates a button labeled "Go to About" that navigates to the `/about` route when clicked. + +=== Test the Navigation + +Now, run the application and navigate to the main view. You should see the "Link to About" link and the "Go to About" button. Clicking either of them should navigate you to the `AboutView`. + + +== Final Thoughts + +You've now explored different ways to navigate between views. Here's what you've learned: + +* Creating a navigation link using `NavLink` component from `react-router` library. +* Programmatically navigating using the `useNavigate` hook from `react-router` library. +* Navigating between React views and Flow views. + +Now that you know how to navigate between views, check out the <<../pass-data#,Pass Data to a View>> guide to learn how to pass data to a view while navigating to it. diff --git a/articles/building-apps/views/navigate/react.adoc b/articles/building-apps/views/navigate/react.adoc deleted file mode 100644 index 335f726d51..0000000000 --- a/articles/building-apps/views/navigate/react.adoc +++ /dev/null @@ -1,12 +0,0 @@ ---- -title: React -page-title: How to navigate to a view in React | Vaadin -description: TODO Write a description -meta-description: TODO Write a meta description -order: 10 ---- - - -= Navigation in React - -TODO \ No newline at end of file diff --git a/articles/building-apps/views/pass-data/route-parameters/hilla.adoc b/articles/building-apps/views/pass-data/route-parameters/hilla.adoc new file mode 100644 index 0000000000..f05f878e28 --- /dev/null +++ b/articles/building-apps/views/pass-data/route-parameters/hilla.adoc @@ -0,0 +1,198 @@ +--- +title: React +page-title: How to use route parameters in React | Vaadin +description: TODO Write a description +meta-description: TODO Write a meta description +tab-title: React +order: 10 +--- + + += Route Parameters in React + +In this guide, you’ll learn how to create a view that accepts a single route parameter. You’ll also explore the differences between required, optional, and wildcard route parameters. Finally, a mini-tutorial helps you apply these concepts in a real Vaadin application. + + +== Required Route Parameters + +To create a React view that accepts a required route parameter, you need to define the parameter name as the view name placed between curly braces (`{}`) followed by the `.tsx` suffix. For example, to create a view that accepts a required `productId` parameter, you should name the view `{productId}.tsx`. The directory structure under the `views` looks like this: + +[source] +---- +views/ +└── products/ + └── {productId}.tsx <1> +---- +<1> The view file that accepts the `productId` parameter. The route is in the form of `/products/{productId}`, where `productId` is a required parameter. Routes such as `/products/123`, `/products/prd222`, etc., match this view. Trying to navigate to `/products` results in a 404 Not Found error unless a view matching the route is defined. + +Though it is technically possible to define the views with parameters directly under the `views` directory, it is recommended to use subdirectories to keep the views organized. + +The routing system also supports having parameters in the middle of the route, which means the directories can also have their names defined with a `{param-name}` convention. Here is an example of a view that accepts a required `productId` parameter: + +[source] +---- +views/ +└── products + └── {productId} <1> + └── edit.tsx +---- +<1> The directory where all its children files have the `productId` parameter in the middle of their routes. The route is in the form of `/products/{productId}/edit`, where `productId` acts as a placeholder for the required parameter, in this case, the product ID. Routes such as `/products/123/edit`, `/products/prd222/edit`, etc., match this view. Trying to navigate to `/products/edit` results in a 404 Not Found error unless a view matching the route is defined. + +=== Accessing Route Parameter Value + +To access the route parameter in the view, use the `useParams` hook from `react-router` in your component. Here is an example of a view that accepts a required `productId` parameter: + +[source,tsx] +.views/products/{productId}.tsx +---- +// tag::snippet[] +import { useParams } from 'react-router'; +// end::snippet[] + +export default function ProductView() { +// tag::snippet[] + const { productId } = useParams(); <1> +// end::snippet[] + + return ( + <> +

Product Details

+

Product ID: {productId}

+ + ); +} +---- +<1> The `useParams` hook returns an object containing the route parameters. In this case, the `productId` parameter is extracted from the object and stored in a variable. + +=== Passing Route Parameter + +To navigate to a view that accepts a route parameter, use the `NavLink` component from `react-router`. Here is an example of how to create a link to a view located at `/products/123`: + +[source,tsx] +---- +import { NavLink } from 'react-router'; +... +Product 123 +---- + +Another way is to use the `useNavigate` hook to navigate programmatically. Here is an example of how to use `useNavigate` for programmatic navigation: + +[source,tsx] +---- +// tag::snippet[] +import { useNavigate } from 'react-router'; +// end::snippet[] + +function MyComponent() { + const navigate = useNavigate(); + + const handleClick = () => { + navigate('/products/123'); + }; + + return ( + + ); +} +---- + +By using either of the above methods, you can navigate to the `/views/products/{productId}.tsx` view that accepts the `productId` route parameter. If you navigate to `/products/123`, the `productId` parameter is extracted and used in the view to fetch the product details for the given ID. + +If a parameter is expected in the middle of the route, the method for navigating to the view is the same. For example, to navigate to `/products/123/edit`, use the same methods as above. The `useParams` hook extracts the `productId` parameter from the route, and the view fetches the product details for the given ID. + +== Optional Route Parameters + +Views can also have optional route parameters. This means that the view can be navigated to with or without the parameter. To make a route parameter optional, use double curly braces around the parameter name when naming the view file. For example, to create a view that accepts an optional `categoryName` parameter, name the view `{{categoryName}}.tsx`. The directory structure under the `views` looks like this: + +[source] +---- +views/ +└── products + └── {{categoryName}}.tsx <1> +---- + +<1> The view file that accepts the `categoryName` optional parameter. The route for this view is in the form of `/products/{{categoryName}}`, where `categoryName` is an optional parameter. Routes such as `/products`, `/products/electronics`, `/products/clothing`, etc., match this view. Note that a view with an optional parameter should be able to handle both cases when the parameter is present and when it is not. Here is an example of a view that accepts an optional `categoryName` parameter: + +[source,tsx] +.views/products/{{categoryName}}.tsx +---- +import { useParams } from "react-router"; +import { ProductService } from "Frontend/generated/endpoints.js"; +import { useEffect } from "react"; +import { useSignal } from "@vaadin/hilla-react-signals"; + +export default function ProductByCategoriesView() { +// tag::snippet[] + const { categoryName } = useParams(); <1> +// end::snippet[] + const products = useSignal([]); + + useEffect(() => { +// tag::snippet[] + if (categoryName == undefined) { <2> +// end::snippet[] + ProductService.allProducts().then((data) => products.value = data); + } else { + ProductService.productsInCategory(categoryName).then((data) => products.value = data); + } + }, []); + + return ( + <> +

Products from {categoryName ? `'${categoryName}' category` : "all categories"}:

+
+
    {products.value.map((product) => ( +
  • {product}
  • + ))}
+
+ + ); +} +---- +<1> The `useParams` hook returns an object containing the route parameters. In this case, the `categoryName` parameter is extracted from the object and stored in a variable. +<2> The `categoryName` parameter is checked to determine whether it is present or not. If it is not present, all products are fetched. Otherwise, products in the specified category are fetched. + +In the above example, the `ProductByCategoriesView` fetches all products when the `categoryName` parameter is not present. When the `categoryName` parameter is present, it fetches the products in the specified category. The view displays the products in the specified category or all products if the `categoryName` parameter is not present. + + +== Wildcard Route Parameters + +Wildcard route parameters are used to match any number of URL segments. This means when a URL cannot be matched with the other defined routes, the wildcard route is picked as the fallback to handle the navigation. One of the common cases of defining wildcard route parameters when defining the routes in a React application is to properly handle the navigation of users when the route is not found. As the default way of defining the routes is through defining the view files and proper directory structure, adding wildcard route parameters should be done by defining the file name as `{...wildcard}.tsx`. The literal value `wildcard` can be anything that is supported by the filesystem as the filename, but Vaadin recommends to use the `{...wildcard}.tsx` as a conventional standard to make it more readable and intuitive. An example of a view that accepts a wildcard route parameter is shown below: + +[source] +---- +views/ +├── @index.tsx +├── about.tsx +├── contact-us.tsx +└── {...wildcard}.tsx <1> +---- +<1> The view file that accepts the wildcard route parameter. + +The routes that are matched with this view depends on the other defined routes. In this case the `/`, `/about`, and `/contact-us` are mapped to their respective views, and if the user tries to navigate to any other routes such as `/123`, `/orders`, or even `/about/789`, then the `{...wildcard}.tsx` is matched as the fallback, accepting the whole unmatched segment of the URL as the wildcard parameter. The view can then handle the navigation and display a custom 404 Not Found page or redirect the user to the home page. Here is an example of a view that accepts a wildcard route parameter: + +[source, tsx] +.views/{...wildcard}.tsx +---- +import { NavLink, useParams } from "react-router"; + +export default function WildcardView() { + const wildcard = useParams()['*']; <1> + return ( + <> +

Page Not Found!

+
+ The '/{wildcard}' route does not exist. + Go back to the home page. +
+ + ); +} +---- +<1> The wildcard route parameter can be extracted using the `useParams` hook, which is stored in the params object with the `*` (asterisk) as the key. The matched wildcard parameters can have many segments, and all the segments is extracted at once when reading the params object with the `*` (asterisk) as the key. + + + +== Try It diff --git a/articles/building-apps/views/pass-data/route-parameters/react.adoc b/articles/building-apps/views/pass-data/route-parameters/react.adoc deleted file mode 100644 index 332b7652b6..0000000000 --- a/articles/building-apps/views/pass-data/route-parameters/react.adoc +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: React -page-title: How to use route parameters in React | Vaadin -description: TODO Write a description -meta-description: TODO Write a meta description -tab-title: React -order: 10 ---- - - -= Route Parameters in React