diff --git a/docs/images/tutorials/javascript/react-app/alert-window.png b/docs/images/tutorials/javascript/react-app/alert-window.png new file mode 100644 index 00000000000..7f0aec591c2 Binary files /dev/null and b/docs/images/tutorials/javascript/react-app/alert-window.png differ diff --git a/docs/images/tutorials/javascript/react-app/browser-development-run.png b/docs/images/tutorials/javascript/react-app/browser-development-run.png new file mode 100644 index 00000000000..67ecde22f42 Binary files /dev/null and b/docs/images/tutorials/javascript/react-app/browser-development-run.png differ diff --git a/docs/images/tutorials/javascript/react-app/continuous-mode.png b/docs/images/tutorials/javascript/react-app/continuous-mode.png new file mode 100644 index 00000000000..7df5f112d9f Binary files /dev/null and b/docs/images/tutorials/javascript/react-app/continuous-mode.png differ diff --git a/docs/images/tutorials/javascript/react-app/current-layout.png b/docs/images/tutorials/javascript/react-app/current-layout.png new file mode 100644 index 00000000000..b47e783f919 Binary files /dev/null and b/docs/images/tutorials/javascript/react-app/current-layout.png differ diff --git a/docs/images/tutorials/javascript/react-app/deployment-to-production.png b/docs/images/tutorials/javascript/react-app/deployment-to-production.png new file mode 100644 index 00000000000..86b1fb298e8 Binary files /dev/null and b/docs/images/tutorials/javascript/react-app/deployment-to-production.png differ diff --git a/docs/images/tutorials/javascript/react-app/edit-configurations-continuous.png b/docs/images/tutorials/javascript/react-app/edit-configurations-continuous.png new file mode 100644 index 00000000000..931d01a2fa3 Binary files /dev/null and b/docs/images/tutorials/javascript/react-app/edit-configurations-continuous.png differ diff --git a/docs/images/tutorials/javascript/react-app/hello-react-js.png b/docs/images/tutorials/javascript/react-app/hello-react-js.png new file mode 100644 index 00000000000..14952b06588 Binary files /dev/null and b/docs/images/tutorials/javascript/react-app/hello-react-js.png differ diff --git a/docs/images/tutorials/javascript/react-app/red-page.png b/docs/images/tutorials/javascript/react-app/red-page.png new file mode 100644 index 00000000000..7f66ac7ddd0 Binary files /dev/null and b/docs/images/tutorials/javascript/react-app/red-page.png differ diff --git a/docs/images/tutorials/javascript/react-app/social-buttons.png b/docs/images/tutorials/javascript/react-app/social-buttons.png new file mode 100644 index 00000000000..7c58c317251 Binary files /dev/null and b/docs/images/tutorials/javascript/react-app/social-buttons.png differ diff --git a/docs/images/tutorials/javascript/react-app/structured-layout.png b/docs/images/tutorials/javascript/react-app/structured-layout.png new file mode 100644 index 00000000000..aac395ed272 Binary files /dev/null and b/docs/images/tutorials/javascript/react-app/structured-layout.png differ diff --git a/docs/images/tutorials/javascript/react-app/two-videos-select.png b/docs/images/tutorials/javascript/react-app/two-videos-select.png new file mode 100644 index 00000000000..3846dd92b2e Binary files /dev/null and b/docs/images/tutorials/javascript/react-app/two-videos-select.png differ diff --git a/docs/images/tutorials/javascript/react-app/website-api-data.png b/docs/images/tutorials/javascript/react-app/website-api-data.png new file mode 100644 index 00000000000..7eedf1893fa Binary files /dev/null and b/docs/images/tutorials/javascript/react-app/website-api-data.png differ diff --git a/docs/images/tutorials/javascript/react-app/website-draft.png b/docs/images/tutorials/javascript/react-app/website-draft.png new file mode 100644 index 00000000000..8992fa29672 Binary files /dev/null and b/docs/images/tutorials/javascript/react-app/website-draft.png differ diff --git a/docs/kr.tree b/docs/kr.tree index 6d823e41904..055f399945b 100644 --- a/docs/kr.tree +++ b/docs/kr.tree @@ -179,7 +179,7 @@ - + diff --git a/docs/topics/getting-started.md b/docs/topics/getting-started.md index 0e3737f161c..2ee8d2af061 100644 --- a/docs/topics/getting-started.md +++ b/docs/topics/getting-started.md @@ -126,7 +126,7 @@ Here you'll learn how to develop and improve your frontend web application using 2. **Create your first frontend web application:** * To start from scratch, [create a basic browser application with the IntelliJ IDEA project wizard](js-project-setup.md). - * If you prefer more robust examples, complete the [Building Web Applications with React and Kotlin/JS](https://play.kotlinlang.org/hands-on/Building%20Web%20Applications%20with%20React%20and%20Kotlin%20JS/01_Introduction) hands-on tutorial. It includes a sample project that can serve as a good starting point for your own projects, and contains useful snippets and templates. + * If you prefer more robust examples, complete the [Build a web application with React and Kotlin/JS](js-react.md) tutorial. It includes a sample project that can serve as a good starting point for your own projects, and contains useful snippets and templates. * Check out the list of [Kotlin/JS samples](js-samples.md) for more ideas on how to use Kotlin/JS. 3. **Use libraries in your application.** Learn more about [adding dependencies](js-project-setup.md#dependencies). diff --git a/docs/topics/js/js-get-started.md b/docs/topics/js/js-get-started.md index f0e2b4904b3..9c992dd142a 100644 --- a/docs/topics/js/js-get-started.md +++ b/docs/topics/js/js-get-started.md @@ -130,13 +130,13 @@ Enter your name in the text box and accept the greetings from your application! ## What's next? -Once you have created your first application, you can go to Kotlin hands-on labs and complete long-form Kotlin/JS tutorials +Once you have created your first application, you can complete long-form Kotlin/JS tutorials or check out the list of Kotlin/JS sample projects for inspiration. Both types of resources contain useful snippets and patterns and can serve as a nice jump-off point for your own projects. -### Hands-on labs +### Tutorials -* [Building Web Applications with React and Kotlin/JS](https://play.kotlinlang.org/hands-on/Building%20Web%20Applications%20with%20React%20and%20Kotlin%20JS/01_Introduction) +* [Build a web application with React and Kotlin/JS — tutorial](js-react.md) guides you through the process of building a simple web application using the React framework, shows how a type-safe Kotlin DSL for HTML makes it easy to build reactive DOM elements, and illustrates how to use third-party React components and obtain information from APIs, all while writing the whole application logic in pure Kotlin/JS. diff --git a/docs/topics/js/js-hands-ons.md b/docs/topics/js/js-hands-ons.md deleted file mode 100644 index 5327cc24f91..00000000000 --- a/docs/topics/js/js-hands-ons.md +++ /dev/null @@ -1,20 +0,0 @@ -[//]: # (title: Hands-on labs for Kotlin/JS) - -Hands-on labs are long-form tutorials that help you get to know a technology by guiding you through -a self-contained project related to a specific topic. - -They include sample projects, which can serve as jumping-off points for your own projects, and contain useful snippets and patterns. - -For Kotlin/JS, the following hands-on labs are currently available: - -* [Building Web Applications with React and Kotlin/JS](https://play.kotlinlang.org/hands-on/Building%20Web%20Applications%20with%20React%20and%20Kotlin%20JS/) -guides you through the process of building a simple web application - using the React framework, shows how a typesafe Kotlin DSL for HTML makes it convenient to build reactive DOM elements, - and illustrates how to use third-party React components, and how to obtain information from APIs, - while writing the whole application logic in pure Kotlin/JS. -* [Building a Full Stack Web App with Kotlin Multiplatform](https://play.kotlinlang.org/hands-on/Full%20Stack%20Web%20App%20with%20Kotlin%20Multiplatform/) -teaches the concepts behind building an application that targets Kotlin/JVM and Kotlin/JS by building a client-server application -that makes use of common code, serialization, and other multiplatform paradigms. -It also provides a brief introduction into working with Ktor both as a server- and client-side framework. - -We are continuously working on expanding the set of hands-on labs to make it as easy as possible for you to learn more about Kotlin/JS and adjacent technologies. \ No newline at end of file diff --git a/docs/topics/js/js-overview.md b/docs/topics/js/js-overview.md index 9e547b43c1b..bb36946d421 100644 --- a/docs/topics/js/js-overview.md +++ b/docs/topics/js/js-overview.md @@ -120,12 +120,12 @@ main Kotlin/JS benefits, shares some tips and use cases, and talks about the pla If you're new to Kotlin, a good first step is to familiarize yourself with the [basic syntax](basic-syntax.md) of the language. To start using Kotlin for JavaScript, please refer to [Set up a Kotlin/JS project](js-project-setup.md). You can also -pick a [hands-on](#hands-on-labs-for-kotlin-js) lab to work through or check out the list of [Kotlin/JS sample projects](#sample-projects-for-kotlin-js) +complete a [tutorial](#tutorials-for-kotlin-js) to work through or check out the list of [Kotlin/JS sample projects](#sample-projects-for-kotlin-js) for inspiration. They contain useful snippets and patterns and can serve as nice jump-off points for your own projects. -## Hands-on labs for Kotlin/JS +### Tutorials for Kotlin/JS -* [Building Web Applications with React and Kotlin/JS](https://play.kotlinlang.org/hands-on/Building%20Web%20Applications%20with%20React%20and%20Kotlin%20JS/01_Introduction) +* [Build a web application with React and Kotlin/JS — tutorial](js-react.md) guides you through the process of building a simple web application using the React framework, shows how a type-safe Kotlin DSL for HTML makes it easy to build reactive DOM elements, and illustrates how to use third-party React components and obtain information from APIs, all while writing the whole application logic in pure Kotlin/JS. @@ -135,7 +135,7 @@ teaches the concepts behind building an application that targets Kotlin/JVM and application that makes use of shared code, serialization, and other multiplatform paradigms. It also provides a brief introduction to working with Ktor both as a server- and client-side framework. -## Sample projects for Kotlin/JS +### Sample projects for Kotlin/JS * [Full-stack Spring collaborative to-do list](https://github.com/Kotlin/full-stack-spring-collaborative-todo-list-sample) shows how to create a to-do list for collaborative work using `kotlin-multiplatform` with JS and JVM targets, Spring diff --git a/docs/topics/js/js-react.md b/docs/topics/js/js-react.md new file mode 100644 index 00000000000..73cf0aa2dc4 --- /dev/null +++ b/docs/topics/js/js-react.md @@ -0,0 +1,1308 @@ +[//]: # (title: Build a web application with React and Kotlin/JS — tutorial) + +This tutorial will teach you how to build a browser application with Kotlin/JS and the [React](https://reactjs.org/) +framework. You will: + +* Complete usual kinds of tasks associated with building a typical React application. +* Explore how [Kotlin's DSLs](type-safe-builders.md) can be used to help express concepts concisely and uniformly without +sacrificing readability, allowing to write a fully-fledged application completely in Kotlin. +* Learn how to use ready-made npm components, use external libraries, and publish the final application. + +The output will be a _KotlinConf Explorer_ web app dedicated to the [KotlinConf](https://kotlinconf.com/) event +with links to conference talks. Users will be able to watch all the talks on one page and mark them as seen or unseen. + +The tutorial assumes you have prior knowledge of Kotlin and basic knowledge of HTML and CSS. Understanding the basic +concepts behind React may help understand some sample code but is not strictly required. + +> You can get the final application as well as the intermediate steps [here](https://github.com/kotlin-hands-on/web-app-react-kotlin-js-gradle). +> Each step is available from its own branch and is linked at the bottom of each corresponding section. +> +{type="note"} + +## Before you start + +1. Download and install the latest version of [IntelliJ IDEA](https://www.jetbrains.com/idea/download/index.html). +2. Clone the [project template](https://github.com/kotlin-hands-on/web-app-react-kotlin-js-gradle) and open it in IntelliJ + IDEA. The template includes a basic Kotlin/JS Gradle project with all required configurations and dependencies: + + * Dependencies and tasks in the `build.gradle.kts` file: + + ```kotlin + dependencies { + // React, React DOM + Wrappers + implementation(enforcedPlatform("org.jetbrains.kotlin-wrappers:kotlin-wrappers-bom:1.0.0-pre.354")) + implementation("org.jetbrains.kotlin-wrappers:kotlin-react") + implementation("org.jetbrains.kotlin-wrappers:kotlin-react-dom") + + // Kotlin React Emotion (CSS) + implementation("org.jetbrains.kotlin-wrappers:kotlin-emotion") + + // Video Player + implementation(npm("react-player", "2.10.1")) + + // Share Buttons + implementation(npm("react-share", "4.4.0")) + + // Coroutines & serialization + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.3") + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.3") + } + ``` + + * An HTML template page in `src/main/resources/index.html` for inserting the JS code: + + ```html + + + + + Hello, Kotlin/JS! + + +
+ + + + ``` + {validate="false"} + + Kotlin/JS projects are automatically bundled with all of your code and its dependencies into a single JavaScript file +with the same name as the project: `confexplorer.js` when you build them. As a typical [JavaScript convention](https://faqs.skillcrush.com/article/176-where-should-js-script-tags-be-linked-in-html-documents), +the content of the body (including the `root` div) is loaded first to ensure that the browser loads all page elements +before the scripts. + +* A code snippet in `src/main/kotlin/Main.kt`: + + ```kotlin + import kotlinx.browser.document + + fun main() { + document.bgColor = "red" + } + ``` + +### Run the development server + +The Kotlin/JS Gradle plugin comes by default with support for an embedded `webpack-dev-server`, allowing to run +the application from the IDE without manually setting up any server. + +To test that the program successfully runs inside the browser, start the development server by invoking the `run` or +`browserDevelopmentRun` (available in the `other` or `kotlin browser` directory) task from the Gradle tool window inside +IntelliJ IDEA: + +![Gradle tasks list](browser-development-run.png){width=700} + +To run the program from the Terminal, use `./gradlew run` instead. + +When the project is compiled and bundled, a red, blank page will appear in a browser window: + +![Blank red page](red-page.png){width=700} + +### Enable hot reload / continuous mode + +Configure the _[continuous compilation](dev-server-continuous-compilation.md)_ mode, instead of manually compiling and +executing your project every time the changes are made. Make sure to stop all running development server instances before +proceeding. + +1. Edit a run configuration that IntelliJ IDEA automatically generates after running the Gradle `run` task for the first time: + + ![Edit a run configuration](edit-configurations-continuous.png){width=700} + +2. In the **Run/Debug Configurations** dialog, add the `--continuous` option to the arguments for the run configuration: + + ![Enable continuous mode](continuous-mode.png){width=700} + + After applying the changes, you can use the **Run** button inside IntelliJ IDEA to start the development server back up. + To run the Gradle continuous builds from the Terminal, use `./gradlew run --continuous` instead. + +3. To test this feature, change the color of the page to blue in the `Main.kt` file while the Gradle task is running: + + ```kotlin + document.bgColor = "blue" + ``` + + The project then recompiles, and after a reload the browser will show the new color. + +You can keep the development server running in the continuous mode during the development process. It will automatically +rebuild and reload the page when you make changes. + +> You can find this state of the project on the `master` branch [here](https://github.com/kotlin-hands-on/web-app-react-kotlin-js-gradle/tree/master). +> +{type="note"} + +## Create a web app draft + +### Add the first static page with React + +To make your app display a simple message, replace the code in the `Main.kt` file as follows: + +```kotlin +import kotlinx.browser.document +import react.* +import emotion.react.css +import csstype.Position +import csstype.px +import react.dom.html.ReactHTML.h1 +import react.dom.html.ReactHTML.h3 +import react.dom.html.ReactHTML.div +import react.dom.html.ReactHTML.p +import react.dom.html.ReactHTML.img +import react.dom.client.createRoot +import kotlinx.serialization.Serializable + +fun main() { + val container = document.getElementById("root") ?: error("Couldn't find root container!") + createRoot(container).render(Fragment.create { + h1 { + +"Hello, React+Kotlin/JS!" + } + }) +} +``` +{validate="false"} + +* The `render()` function instructs [kotlin-react-dom](https://github.com/JetBrains/kotlin-wrappers/tree/master/kotlin-react-dom) + to render a first HTML element inside a [fragment](https://reactjs.org/docs/fragments.html) to the `root` element. + This element is a container defined in `src/main/resources/index.html`, which was included in the template. +* The content is an `

` header and uses a typesafe DSL to render HTML. +* `h1` is a function that takes a lambda parameter. When you add the `+` sign in front of the string literal, + the `unaryPlus()` function is actually invoked using [operator overloading](operator-overloading.md). + It appends the string to the enclosed HTML element. + +When the project recompiles, the browser displays this HTML page: + +![An HTML page example](hello-react-js.png){width=700} + +### Convert HTML to Kotlin's typesafe HTML DSL + +The Kotlin [wrappers](https://github.com/JetBrains/kotlin-wrappers/blob/master/kotlin-react/README.md) for React come +with a [domain-specific language (DSL)](type-safe-builders.md) that allows writing HTML in +pure Kotlin code. In this way, it's similar to [JSX](https://reactjs.org/docs/introducing-jsx.html) from JavaScript. +However, with this markup being Kotlin, you get all the benefits of a statically typed language, such as autocomplete or +type checking. + +Compare classic HTML code for the future web app and its typesafe variant in Kotlin: + + + + +```html +

KotlinConf Explorer

+
+

Videos to watch

+

John Doe: Building and breaking things

+

Jane Smith: The development process

+

Matt Miller: The Web 7.0

+

Videos watched

+

Tom Jerry: Mouseless development

+
+
+

John Doe: Building and breaking things

+ +
+``` + +
+ + +```kotlin +h1 { + +"Hello, React+Kotlin/JS!" +} +div { + h3 { + +"Videos to watch" + } + p { + + "John Doe: Building and breaking things" + } + p { + +"Jane Smith: The development process" + } + p { + +"Matt Miller: The Web 7.0" + } + h3 { + +"Videos watched" + } + p { + +"Tom Jerry: Mouseless development" + } +} +div { + h3 { + +"John Doe: Building and breaking things" + } + img { + src = "https://via.placeholder.com/640x360.png?text=Video+Player+Placeholder" + } +} +``` + + +
+ +Copy the Kotlin code and update the `Fragment.create()` function call inside the `main()` function, replacing the previous `h1` tag. + +Wait for the browser to reload. The page should now look like this: + +![The web app draft](website-draft.png){width=700} + +### Add videos using Kotlin constructs in markup + +There are some advantages in writing HTML in Kotlin using this DSL. You can manipulate your app using regular Kotlin +constructs, like loops, conditions, collections, string interpolation + +You can now replace the hardcoded list of videos with a list of Kotlin objects: + +1. In `Main.kt`, create a `Video` [data class](data-classes.md) to hold together video attributes: + + ```kotlin + data class Video( + val id: Int, + val title: String, + val speaker: String, + val videoUrl: String + ) + ``` + +2. Fill up the two lists for unwatched videos and watched videos, respectively. Add these declarations at + file-level in `Main.kt`: + + ```kotlin + val unwatchedVideos = listOf( + Video(1, "Opening Keynote", "Andrey Breslav", "https://youtu.be/PsaFVLr8t4E"), + Video(2, "Dissecting the stdlib", "Huyen Tue Dao", "https://youtu.be/Fzt_9I733Yg"), + Video(3, "Kotlin and Spring Boot", "Nicolas Frankel", "https://youtu.be/pSiZVAeReeg") + ) + + val watchedVideos = listOf( + Video(4, "Creating Internal DSLs in Kotlin", "Venkat Subramaniam", "https://youtu.be/JzTeAM8N1-o") + ) + ``` + +3. To use these videos on the page, write a Kotlin `for` loop to iterate over the collection of unwatched `Video` objects. +Replace the three `p` tags under "Videos to watch" with the following snippet: + + ```kotlin + for (video in unwatchedVideos) { + p { + +"${video.speaker}: ${video.title}" + } + } + ``` + +4. Apply the same process to modify the code for the single tag following "Videos watched" as well: + + ```kotlin + for (video in watchedVideos) { + p { + +"${video.speaker}: ${video.title}" + } + } + ``` + +Wait for the browser to reload. The layout should stay the same as before. You can add some more videos to the list to make +sure that the loop is working. + +### Add styles with typesafe CSS + +The [kotlin-emotion](https://github.com/JetBrains/kotlin-wrappers/blob/master/kotlin-emotion/) wrapper for the [Emotion](https://emotion.sh/docs/introduction) +library allows specifying CSS attributes – even dynamic ones – right alongside HTML with JavaScript. Conceptually, that +makes it similar to [CSS-in-JS](https://reactjs.org/docs/faq-styling.html#what-is-css-in-js) – but for Kotlin. +The benefit of using a DSL is that you can use Kotlin code constructs to express formatting rules. + +The template project for this tutorial already includes the dependency needed to use `kotlin-emotion`: + +```kotlin +dependencies { + // ... + // Kotlin React Emotion (CSS) (chapter 3) + implementation("org.jetbrains.kotlin-wrappers:kotlin-emotion") + // ... +} +``` + +With `kotlin-emotion`, you can specify a `css` block inside HTML elements `div` and `h3`, where you can define the styles. + +To move the video player to the top right corner of the page, use CSS and adjust the code for the video player +(the last `div` in the snippet): + +```kotlin +div { + css { + position = Position.absolute + top = 10.px + right = 10.px + } + h3 { + +"John Doe: Building and breaking things" + } + img { + src = "https://via.placeholder.com/640x360.png?text=Video+Player+Placeholder" + } +} +``` + +Feel free to experiment with some other styles. For example, you could change the `fontFamily`, or add some `color` to your UI. + +> You can find this state of the project on the `02-first-static-page` branch [here](https://github.com/kotlin-hands-on/web-app-react-kotlin-js-gradle/tree/02-first-static-page). +> +{type="note"} + +## Design app components + +The basic building blocks in React are called _[components](https://reactjs.org/docs/components-and-props.html)_. +Components themselves can also be composed of other, smaller components. By combining components, you build your application. +If you structure components to be generic and reusable, you'll be able to use them in multiple parts of the app without +duplicating code or logic. + +The content of the `render()` function generally describes a basic component. The current layout of your application looks +like this: + +![Current layout](current-layout.png){width=700} + +If you decompose your application into individual components, you'll end up with a more structured layout, in which +each component handles its responsibilities: + +![Structured layout with components](structured-layout.png){width=700} + +Components encapsulate a particular functionality. Using components shortens source code and makes it easier to read and +understand. + +### Add the main component + +To start creating application structure, first explicitly specify the main component for rendering into the `root` +element, the `App`: + +1. Create a new `App.kt` file in the `src/main/kotlin` folder. +2. Inside this file, add the following snippet, and move the typesafe HTML from `Main.kt` into the snippet: + + ```kotlin + import kotlinx.coroutines.async + import react.* + import react.dom.* + import kotlinx.browser.window + import kotlinx.coroutines.* + import kotlinx.serialization.decodeFromString + import kotlinx.serialization.json.Json + import emotion.react.css + import csstype.Position + import csstype.px + import react.dom.html.ReactHTML.h1 + import react.dom.html.ReactHTML.h3 + import react.dom.html.ReactHTML.div + import react.dom.html.ReactHTML.p + import react.dom.html.ReactHTML.img + + val App = FC { + // typesafe HTML goes here, starting with the first h1 tag! + } + ``` + + The `FC` function creates a [function component](https://reactjs.org/docs/components-and-props.html#function-and-class-components). + +3. In the `Main.kt` file, update the `main()` function as follows: + + ```kotlin + fun main() { + val container = document.getElementById("root") ?: error("Couldn't find root container!") + createRoot(container).render(App.create()) + } + ``` + + Now the program creates an instance of the `App` component and renders it to the specified container. + +For more information on React concepts, see its [documentation and guides](https://reactjs.org/docs/hello-world.html#how-to-read-this-guide). + +### Extract a list component + +Since the `watchedVideos` and `unwatchedVideos` lists both contain a list of videos, it makes sense to create a single +reusable component, and only adjust the content displayed in the lists. + +The `VideoList` component follows the same pattern as the `App` component. It uses the `FC` builder function, +and contains the code from the `unwatchedVideos` list. + +1. Create a new `VideoList.kt` file in the `src/main/kotlin` folder and add the following code: + + ```kotlin + import kotlinx.browser.window + import react.* + import react.dom.* + import react.dom.html.ReactHTML.p + + val VideoList = FC { + for (video in unwatchedVideos) { + p { + +"${video.speaker}: ${video.title}" + } + } + } + ``` + +2. In `App.kt`, use the `VideoList` component by invoking it without parameters: + + ```kotlin + // . . . + div { + h3 { + +"Videos to watch" + } + VideoList() + + h3 { + +"Videos watched" + } + VideoList() + } + // . . . + ``` + + For now, the `App` component has no control over the content that is shown by the `VideoList` component. It's hard-coded, + so you see the same list twice. + +### Add props to pass data between components + +For reusing the `VideoList` component, it should be possible to fill it with different content. You can add +the ability to pass the list of items as an attribute to the component. In React, these attributes are called _props_. +When the props of a component are changed in React, the framework automatically re-renders the component. + +For `VideoList`, you'll need a prop containing the list of videos to be shown. Define an interface +that holds all the props which can be passed to a `VideoList` component: + +1. Add the following definition to the `VideoList.kt` file: + + ```kotlin + external interface VideoListProps : Props { + var videos: List