React Native Crash Course | Build a Complete App

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
Hi and welcome to this course on React Native. My name is Max, and in this course I'll teach you React Native from the ground up. And React Native is an amazing library building up on the React, on the React library, allowing you to build real native mobile apps for iOS and Android with React. And therefore, I'd suggest let's not waste any time, let's dive right in. And let's start with the most important question first: What exactly is React Native and how does it work? - [Maximilian] So, what exactly is React Native? Well, as the name applies, it is related to React.js. And with React.js and React Native, you can build real React Native based mobile apps for iOS and Android, which are real apps you can distribute through the app stores and apps that can be used by any user with an iOS or Android device. Now React.js is a library that's independent from React Native though. React.js is a JavaScript library for building user interfaces. And it is typically used for web development. That's also the environment for which it was first created. But actually, if you worked with React.js, you might know that there, it's actually another library the React DOM library that adds the actual web support because React itself, the library React itself, without React DOM is platform-agnostic, which means you can use React in conjunction with React DOM to build web apps, but React the library itself, actually does not care about the underlying platform. React just gives you tools for managing state, for building virtual component trees, and then you need an extra library like React DOM for translating the result React produced to an actual platform like the browser. Now, React Native is basically an alternative to React DOM, therefore. React Native gives you a collection of special react components, which you can use in your JSX code. So React Native ships with built-in components you can use. And those components are then compiled to native UI elements for the iOS and Android platforms, and React Native will also take care about this compilation step. In addition, React Native also exposes certain native platform APIs like using the device camera so that you can use such features in your JavaScript code even though you need to tap into native device APIs for that. And therefore in the end, React Native is like React DOM. It just does not target the web, the browser as a platform, but instead iOS and Android. And React Native gives you all the components and the APIs you need to interact with those platforms and to build apps for those platforms. That is what React Native is all about. And therefore, in order to work with React Native, you also must know React.js because you will write your code in React.js and then just use these extra React Native components and APIs in your React JavaScript code to produce those native mobile apps for iOS and Android. - [Maximilian] Now, how does React Native work Under The Hood though? If you're building a React and React Native app, then you are typically writing code like this which should look very familiar, if you worked with React.js before maybe, or most likely for building browser based apps. This is a React Component what you see here. And it's just one way of writing such a Component. We could also use the function keyword instead of defining an arrow function. And we could also use a class based Component. But it's code like this, which you will write for React Native and it's code like this that will be compiled to Real Native App code. So which will be bundled into a Real Native App in the end. Now, if you take a closer look at the code snippet on the left here, you will see two Components two JSX elements in there, which you don't know from web development, the View and the Text element. These are some of these special Components that are exposed by React Native, which will be compiled by React Native. It is worth noting though, that it's really just the Views. Just this JSX code that is compiled not the JavaScript logic itself. I will come back to that in a second. So the Components, the JSX elements you use are compiled to native elements for the respective platforms. And to make this a bit easier to understand, take a look at this comparison table here, here we got a bunch of elements, as we would use them in the browser if we would be using react-dom and then the equivalence for the native platforms, and then the Components exposed by React Native to target those equivalence. So for example if you want to display an input element where users can enter some text, then when building a web app we would use the HTML input element which is available in JSX when we're using react-dom. If we would be building a native Android app with Java or Kotlin then it would be the built in added text widget that is provided by Android, which we need to build. For iOS it would be the UITextField element and with React Native we would use the built in TextInput Component which is provided by React Native and which will then be compiled to added text for Android or to UITextField for iOS. So React Native maps and compiles reusable Components like TextInput or View or many other Components about which you will learn throughout the course to their respective platform equivalents. That's one of the main jobs React Native will take care of. But what about the logic? I mentioned that those Views the JSX elements are compiled to their native equivalence. But what about the JavaScript code you write outside of JSX? What about all these functions? If statements? State management? What about that? Well, unlike the UI elements, the logic is not compiled. The UI elements which are those Components exposed by React Native are compiled as you learned, but the logic which you write in JavaScript is actually not compiled but instead it's running on a JavaScript thread that's hosted by React Native in the native app that was built. So React Native basically spins up a simple JavaScript process as part of your native app that's being built. And it manages this process for you. And it allows this process to talk to the underlying native platform and therefore your JavaScript code will run as JavaScript in the native app that's being built but it will then talk to the underlying Android or iOS platform, through a basic translation bridge. You could say that is provided by React Native as part of your native app. That's how you can think about this. And that is it for now. That's how React Native works Under The Hood and what it does for you. You don't need to know more. You can of course dive into the official docs if you do want to learn more but that is what you should know in order to work with React Native, because I believe it's always important to have a basic understanding of how a tool works. And this is how React Native works. - [Maximilian] So I would say it's enough for the theory for now. Let's get started. And for that, you can simply search for React Native, to find React Native dot dev, which is the official React Native website. Now on this site, you can learn more about React Native and it is a great additional resource if you do wanna dive deeper and learn more about it, but of course you will learn all the essentials and everything you need to know to build React Native apps, in this course. Now in here, on this side, it is a good idea to click on get started though, because there you'll learn how you can create a React Native project. And what you will learn here, is that if you do click on environment set up here, on setting up the development environment, that you got two choices. That you can use a tool called Expo CLI, which seems to be recommended because it's the by default selected choice. And that you can use the React Native CLI. Now, as I just said, Expo CLI is selected by default and indeed it is my recommendation as well and it is the tool we will use in this course. But you could also use this alternative approach. Both approaches will give you a development environment in which you can build React Native apps. So what's the difference then? Then we have the Expo CLI and the React Native CLI. CLI stands for command line interface and both tools are tools that exist in order to help you create React Native projects and run React Native apps on testing devices and simulators, as well as build React Native apps so that you can ship them to the app stores. So these are the tools you need to really build apps and to get those packages, those distributable packages, which you can upload to the app stores. These two tools are crucial, but you don't need to use them both. You can use either of the two and one tool is enough. But why do we have these two tools? And what's the difference? Well, the Expo CLI, or just Expo as I will also call it throughout the course, and the company behind this CLI is in the end a third party service that you can use. A service that is entirely free. You don't have to sign up, you don't have to pay for it. You can sign up and you can pay, they do offer extra paid services but to build React Native apps and to ship them you don't need to pay. When using Expo, the CLI, and a couple of other free tools which they give you, you get a managed app development workflow, as I like to call it, which means creating projects is easy, writing code is a bit easier, tapping into Native device functionalities, like using the device camera and so on, is easier and in general, when using Expo, the Expo CLI and also couple of other tools provided by Expo, writing Native apps with React Native is more convenient than with just the React Native CLI and without Expo. There is less friction to this process. And the best thing is that you can still leave this Expo approach and ecosystem anytime, if you need to. If you start by using Expo because it's easier to get started with that and then at a later point you find out that you wanna switch to just using the React Native CLI workflow and not using Expo. You can do this anytime. That's why it's also the default selection to start with Expo, because it's easier and you can still switch anytime you want to. Now, why do we have the React Native CLI then? Well, because it existed before we had Expo because this is the tool provided by the React Native team and the community around React Native. It gives you a barebone React Native development setup. Which means you will need to do more configuration and setup work on your own. There are less convenience features, and if you need to tap into certain Native device features, like using the camera or other features, then it is often a bit more work when not having Expo around because, as mentioned before, Expo is not just about the tool that creates projects, it will also give you helpful packages and tools that you can use when writing code, that will make your life easier in that case as well. Now, what the pure React Native workflow does have though is that it is often a bit easier to integrate with Native source code. So with source code written in Java, or Objective-C, or SWIFT or Kotlin. So if you must mix JavaScript code and Native device source code, then using just their React Native CLI could be beneficial. But the idea behind React Native is that you don't have to do this too often and therefore this might not really be an advantage. And for all these reasons, and especially since you can switch anytime if you need to, we will use Expo in this course. As you will see it's super easy to get started with that and it will make building React Native apps much easier. - [Maximilian] Therefore, back here on the official React Native website, we will stick to this Expo CLI quick start approach here, and we need to run this command in order to install the Expo CLI, which is the tool that will then allow us to create Expo-based React Native projects. Now, we do install this tool with NPM, which is the Node Package Manager, and therefore, you need to install Node.js. Now, we don't need to install Node.js because we will write any Node.js code, but simply because we need to install this package, and also because Node will be used by some packages under the hood. Hence, you should visit nodejs.org and make sure that you download the LTS version from there, which in my case is version 16, but simply download whatever the LTS version is for you when you are viewing this. I will download this and simply walk through the installer. And there is an installer for both Windows, macOS, and also for Linux, so you can and should install this on whatever device you are on. And once you do have Node.js installed, you are ready to run this command in your terminal or command prompt. Here I'm in my terminal, and in there, I'll just paste in this command, and I'm on macOS where I must add a sudo in front of this command in order to make it work. You might not need to do this, you definitely don't need to add this on Windows because this is not a Windows command. On Windows, you just execute NPM install -g expo-CLI, but on macOS and Linux, you might need to add this, especially if you are getting some permissions error otherwise. With that, I will install this by also entering my password here and this will now download and install this Expo CLI tool globally, that's what -g does, on my system here. I will be back once this finished. Here it finished for me. You can ignore any warnings you might have gotten here. It did finish successfully if you can run the Expo command thereafter and you don't get an error when trying to do this. Now this, by the way, shows you all the commands you can then execute with Expo. There are a lot. And the official Expo documentation is the place to go if you wanna learn more about that. You do find that documentation on expo.dev, but we don't need to take a closer look at those commands right now because there's only one command we need to run right now and that is expo init, which initializes a new project. But since I'm already on this official website, as always, you might wanna explore those docs in addition to this course, simply because in there you can learn more about Expo, the philosophy behind Expo, how you could switch to a React Native only project, though we will take a look at this later in the course, as well, and how you can use it. This is a great backup resource in addition to this course. Now, here we did now install Expo. Now we can create a new project by running expo init. For this, I switched to another folder here on my system, the folder where I wanna create this new project. I switched to it here in the terminal with the CD command, which you can also use on Windows in the command prompt to switch folders and pops. And then, in the place where I wanna create my new project folder, I will run expo init, and then I'll name my project RNCourse here. This will be the name of the folder which will be created and the default name of the app that will be created in that project folder. If we now hit enter, we get a little menu here where we can choose which kind of project we wanna create. The options and the text here could change over time. Right now, I can choose a blank project, a blank project with TypeScript support, a project that already has navigation added to it, which we will take a look at later in the course, or a bare workflow project, which is actually a project that doesn't use too much Expo. But again, we will take a look at that later in the course. Right now, we wanna have such a managed workflow project where we fully embrace Expo and take advantage of it, and I don't wanna use TypeScript, I also don't wanna use navigation right now. We will add it later. Hence, I'll just use blank here. And this will now create a new blank Expo React Native project in a folder named RNCourse since that is the name I chose here. Now, this did now create this project folder and it shows us some commands we could execute in there to start the Expo Development Server, which will basically watch our code and create a development app bundle whenever we change the code. And we can then also run that code in preview mode on iOS and Android, and even for the web, though that's not the focus of this course. If you wanna build React web apps, then my React Complete Guide is the best choice. Here we'll focus on Android and IOS. Nonetheless, I'll not execute those commands right now. Instead, I wanna open this new project first so that we can see what was created in greater detail. - So we created this project, this expert project before we run it now, I wanna open the created project in an editor that allows me to edit the code in a convenient way. Now you can use any code editor you want, My recommendation is Visuals Studio Code, which is an amazing free code editor, That's very extensible and fun to use. You can download it for all platforms. And I already do have installed it for Mac OS. Now with vscode installed, you can open it and you might see a welcome screen. If you installed it for the first time, you can simply close that screen. And then you should see something like this, where you can open a new folder. Alternatively, you can always go to the menu file and find open on Windows, or open folder on Mac OS still. And then if you click that, it will open such a file picker, where you can now select that project folder you just created. So here I'm selecting this RNCOURSE folder which I created before, and I'll open this in vscode. So here I got this expo react-native project opened up and you can of course configure the visuals, the way vscode looks, however you want. by going to view appearance, you can hide or show the sidebar, the status bar at the bottom, and you can also go to preferences and then choose a color theme, that suits your needs. I'm using the dark plus theme here. so you can configure this editor however you want but what was created for us here? Well, we see actually not too much. We got two folders, expo-shared and vscode which we can ignore, vscode just holds some settings i configured for this workspace here, And expo-shared simply just holds some internally used information. The assets folder will become important later, because we can store images there. For example, the icon of our app but also images which be used inside our app. And we got the node modules folder which holds all the third party packages that are used under the hood. We got a package, Json file which lists all the dependencies of our project here. And here For example, we see expo because expo is not just the command line interface. It's all so a JavaScript package which we can use, and which we will use heavily as you see because it gives us many utility functionalities that make writing react-native code easier. But you also see we're using react, react-dom, react-native, and react-native-web, though again, that's not the focus of this course. You could build web apps with react-native but support is a bit clunky. And yeah, we're simply not focusing on that because you could just use react itself. If you want to do that together with react-dom. React-dom of course therefore is also just here because of react-native web. So that's what we have here. We also got a couple of script commands which we could execute with NPM but overall there's nothing fancy in here. And you know, these kinds of files if you worked with react before, which you should have because this course assumes that you have react and JavaScript knowledge. So that's the package, Json file . Package-lock is related to that. And the babbleconfigjs file just configures how code is trans piled under the hood, and unless you know what you're doing you also shouldn't change this file therefore. Now we do have the app Json file, which will become important later because here we can configure some settings and behaviors of our react-native app. And this is a file that will be picked up by expo. When our app is built for preview or for the actual app stores. We can set the name here. We can set some background colors here and we will come back to this file occasionally for configuration. So this is a file, which we have because we're using expo. And then we got App js. This is the only real code file we have in this starter project. The exact content could change over time to make sure that we're all on the same page. I attached my App js file to this lecture so that you can download it and replace yours with it so that you have the same code as I have it. Because we'll build up on this code in the next lectures. This in here is a regular react component which uses special components special js x elements, exposed, bio-react-native. That's what I mentioned before. And then we got some styling which could look a bit weird but I'll come back to how styling works in react-native apps later. So for the moment, this is our app code, and now it would be nice to see this code in action. For this, we need some device on which we can preview it. - [Maximilian] So we got our code opened up here. We created this project with Expo. Now it would be nice to preview our app because of course, whilst we're working on the React Native app, we want to constantly preview it so that we can see our changes and tweak the app as required. It would basically be nice to have the same kind of workflow or a comparable workflow as we have it with the browser and just React when we're building React Web apps. There, we can also create a React project and preview it in the browser. Now thankfully, since we're using Expo, previewing our app on a real device is super easy. You just need an Android device or an iPhone. In my case, I have an iPhone here, but the same is true for Android, and you visit the app store there. And in the app store, you can search for Expo. Now, you should find a Expo Go app. This is an app provided by the company behind the Expo CLI and this Expo package, which is part of our project here. So you can now download this app onto your device. This app is available for the iPhone and for Android devices. And once downloaded, you can open it. Now in here, you can preview your Expo apps that are built on your local computer. To do that, you should open up your terminal or command prompt. Here, I'm using the one integrated into VS Code. You can open this by going to terminal here and opening a new terminal. And this is the default system terminal integrated here into your VS Code. And then in here you can run npm-start. Now, what this will do, (device chiming) is it will actually start the Expo Development Server which watches and builds our code and which builds our code, basically such that we can preview it. And it also gives us a QR code here. You can scan this QR code with your Expo app on Android, not on iOS. I'll come back to this in a second, but on Android, you will have a barcode scanner, a button that allows you to scan this barcode in your Expo Go app which you downloaded. In addition, you also should have a browser tab that opened up where you also find this barcode, and where you will find log messages printed by Expo as your app is running. Now on the iPhone, the scanner is not integrated into the Expo app. Instead, there you need to open your camera and then scan this barcode here or the one in the terminal. And then once you tap to open the link that is sent by that barcode, you should click Open, which opens the Expo Go app. Then you should grant any permissions the app might (device chiming) be asking for. And now you see here that the JavaScript bundle is being built. So the Expo app is being built. The React Native app based on Expo is built and it opens up in this simulator on our real device here. So in this Expo Go app here. We can close this info screen. And now here, we see our app which we're building on our local machine running on a real device. Now we can tell that this is our app by changing this text. If I remove all the text here, and instead I say, "Hello, World," good old "Hello, World" message, and I then save this file, you will see that it basically instantly updates on your phone as well in this Expo Go app which we use for previewing. And this is how simple it is to build and test those Expo based React Native apps with the Expo Go app and why it's so recommended to use this Expo workflow. It simply makes building and testing React Native apps much easier. And this still is a React Native app here. We're just using Expo to make our life a bit easier. - [Maximilian] So, this is how easy it is to get started with Expo and React Native. You can easily create an app and with help of the Expo Go App, you can easily preview it. And you might not need more for now. You can now follow along and preview your app changes on your real device. But maybe you don't want use your real device only. Maybe you also have an iPhone and you wanna also preview the app on Android but you don't have an Android device. For those reasons, you might want to install a simulator which is an extra piece of software that runs on your local machine that simulates an iOS device or an Android device. Now, for this, you can search for Android studio, to download Android studio to get such a piece of software that allows you to run Android emulators on your local machine. On developer.android.com/studio. You will find a download link that allows you to download Android studio for your operating system. And this can be downloaded for Mac Os and Windows. Now the download can take a while but make sure you do download and install it in order to be able to run emulators on your local device. Now for iOS, it's different. There you must open the app store on Mac Os and search for Xcode and download this Xcode tool which is Apple's developer environment for building iOS apps. Unfortunately, this is not available for Windows or Linux devices. So if you are on a Windows or a Linux machine, you can't run iOS simulators through Xcode. This is a limitation applied by Apple. So unfortunately on Windows or Linux you can only build and test for Android. Actually, you will be able to build real iOS apps as well through some Cloud build service about which I'll talk a little bit later but when it comes to previewing the app on an iPhone if you don't own a real iPhone on which you can use the Expo go app or a Mac Os device on which you can install Xcode you have to focus on Android instead. It is what it is. Now, once you did install Android studio, you can open it and you should see a welcome screen that looks something like this and that should have some more actions button. And in there you will find a Virtual Device Manager. You can use this manager to build virtual devices so to build emulators. So here I already have an emulator but you can click on create device to build a new one. And here you can select from a broad variety of presets like the pixel five, for example, here. Click next, then choose an Android version that will run on this emulator. And here I'll choose the API 32 version which is the latest version in my case, click next keep all the default settings here and click finish. And now this will create such a new emulator. And then you can click the play button to launch this emulator. And this will now launch this emulator on your device. So on your Windows or Mac OS or Linux device. I'll just increase it a little bit here. So that's now an Android phone so to say running on our computer. Of course just a dummy phone, an emulator, but a real phone when it comes to testing Android apps. Now I will show you how to run this app on this emulator in just a second. First, I wanna show you how it would work for Xcode and Mac OS. Which as mentioned only works on Mac OS. Here in Xcode you wanna open this as well. You don't have to open a project. You just need to open Xcode, and then you should go to the preferences there. In the preferences make sure you go to locations and here under command line tools make sure you have a version selected here. By default no version is selected and you should do that then select a version here. Once this is done, you can close it. And then we can go back here to our Expo app in Vs Code. Now I used the terminal to run this NPM start process. And this process is still running. You should by the way keep this process running as long as you are working on your code. If you quit this process, your code is not watched anymore. Preview builds are not built anymore and they are not pushed to your connected real devices or simulators anymore. You can always quit this process by pressing control + C and you can then restart it by running MPM start again. But as long as your writing code you should keep it running. Now in there, we have this QR code which we could scan to use the Expo go app on a real device but we can also press A to run it on Android or I to run it on iOS and it will pick those running simulators or start a simulator for you. Nonetheless it doesn't hurt to already start an Android simulator as I did it here so that I can then press A. And now this is opening this on Android. So this app is now built and previewed on this Android emulator. Now, in case you're getting an error like this that is most likely related to the emulator you created. You might wanna create a new emulator and make sure that you create one or that you pick a template that has this placed or icon. Because Expo needs to be able to access this play store. So the play store must be part of the emulator in order to download this Expo go app which is used for previewing onto this emulator. So use an emulator template that has this icon then still the latest version, all the defaults and create this emulator and start that emulator. So now I'm launching a new emulator based on this new template here. And once this finish starting, we can again restart NPM-Start maybe, and then press A again to find this emulator, it will be found automatically by Expo and then it will install this Expo go app onto this emulator and open our app there as well. We get this info screen, which we can close. We get this debug screen here which we can use to reload the app, for example or turn on certain debugging tools. But I will we'll come back to debugging later. We can close this for now and see our app here. So that's Android. Now for iOS development you should go to your applications and locate Xcode and show the package contents off that. Because in there in contents, developer, applications you will find this simulator app. And you can double click on this to start an iOS simulator. Now, in this case, it's an iPhone 13 simulator. You can change this by clicking on it and going to the menu and then under file open simulator you can choose all kinds of devices. But I'll go with iPhone 13 here, and we can all increase this in size to make that a bit easier to view. And now we can press I here. You don't even need to restart NPM start. You can serve the preview on Android and iOS simultaneously. So I just served it on Android. Now I will press I to also started on the iOS simulator which also should be detected automatically. And now Expo will also install the Expo go app on that simulator and open this app in that Expo go app on our simulator. So here it's opening up and after a short while and it only takes that long initially when this is all first installed and set up, of course, after a short while we will see our app preview on this device as well. Here we go, it's loading up now and now we see Hello World here as well. So now we can preview our little application on a real device as I showed it to you a couple of minutes ago, and on those simulators like this. And this process here should always stay up and running as long as your writing code. So we'll just make it smaller. And now we can change our code add a couple of exclamation marks. And if we save this file, this is automatically picked up and reloaded on those apps without us doing anything. You can still manually reload it though by pressing R in this running terminal here this will then manually reload those apps. And that's the development environment we will use for this course. This is now what we need to dive deeper into React Native. And this course here. - [Tutor] So let's dive into React Native and let's of course start with the basics. In this course section, we are going to explore the core React Native concepts. This means that we'll dive into the core React Native Components, and we will start building user interfaces with those Components, but we will of course also dive into styling React Native apps. We will learn how we can style those apps and those Components, such that we can really build the user interface we wanna build. And last but definitely not least, we will explore how we can add interactivity to our app and how we can manage state, how we can make sure that there, for example are buttons that can be clicked and that something meaningful happens when a button is clicked. Now for this, in this course section, we are going to build this demo app here. It's a first simple React Native app which allows you to track your goals. For example, your goals for this course, what you wanna achieve by taking this course or as you are taking this course. In this app, we got a list of goals and we can open a model and overly to add new goals. And once a goal was added, we can also tap the goal to remove it again. This is maybe not the next billion dollar app but it's a great first app to learn about many core fundamentals you must know about React Native. - [Instructor] So, let's dive into React Native. For this, I'm back in this project we created in the first course section. In case you did not create it there or you did remove it thereafter, just make sure you got the development environment set up mentioned there, and then you can download the attached starting project. Once you did that, you will get the same code as I have it here. Just make sure that you open your terminal or command prompt. Here, I'm using the one integrated in this code and that you install all the dependencies this project needs, by running npm install. And once that completed, you can run npm start to this Expo process that watches the code and builds the preview and serves it on our emulators. I'll then press a and i to start and run this app on my running Android and iPhone emulators and simulators. Here you go. These are my two preview devices. Now, and actually as we already got some code on which we worked in the first course section already, and what we have in here in the end is a React component, a Functional React component. And indeed, in this course, we will only work with functional components and React hooks. We will not use class based components. So this is a regular functional component. We also got this Styles constant, this SyleSheet object down there. And I will come back to that in a couple of minutes. At the top of this file, we got some imports and we're importing one component from an Expo related package. And the other components, namely View and Text as well as this SyleSheet object here, from React Native. And Text and View are two of those built in components, actually two of the most important built in components, React Native exposes to you, to use in your JSX code. Because in here, you can't use divs or h2 tags or anything like this. These are HTML elements, which work in the browser when you have a DOM to work with, but they won't work here on a Native device, because Native devices are not browsers. They don't have that DOM, and they don't support those HTML elements. Keep this slide from the first course section in mind, that is how React Native translates different elements into different Native elements for Android and iOS. And that's why these components are exposed by React Native. Now, if you visit the official React Native website, then there, you will find various guides which you can definitely take a look at but you will also find the components tab where you get a list of the components provided by React Native. And as you can tell, we actually don't have that many components here because it turns out that with a couple of core components, you can build any kind of user interface. For example, we got a Button here and Image and Text and View. And especially View and Text and Text Input are super important components which you will use all the time. And as you will learn from this course, you can build very complex user interfaces with those core components that you have here. Now, React Native is all about working with those core components that are built into it. You build your overall app UI and your custom components that might make up that UI, by simply combining those core components. Because these core components, as you learned, are translated into Native UI widgets, Native UI elements for Android and iOS by a React Native. That's why we work with those core components that are provided by React Native. And we can combine them in our React Code, in our JSX code, to build our own components and ultimately our own user interface. So in the end, we just compose our components by combining those core opponents. And if you think about it, that's the same for React for the web. HTML happens to have more elements. There are h1, h2 elements, divs, article section, there are many HTML elements. But in the end, you also just combine those HTML elements to build the web user interface. It's the same here for Native apps. So that's what we do with those components. Of course, another important aspect of building user interfaces in general is that you wanna style those apps. And when using React Native, there is no CSS. You can't write CSS code, because again, it's not a browser, so the CSS language doesn't exist here. Instead, you can, of course, still apply Styles, but you do this either in line, essentially by using props on those core components that are provided or with help of these SyleSheet objects or this SyleSheet object which you already saw in the code before. You therefore. write your styling in JavaScript. And hence, you have no extra styling language. It's all JavaScript, but the React Native team gives you a lot of JavaScript properties which you can set and pass to those core elements, which are similar to the CSS properties. But it's only a subset of the overall CSS property and feature set. But in the end, as you will learn throughout this Course, you get all the important CSS properties and features that you need to build powerful and beautiful user interfaces. But back here in our component code, we can see how these core components that are provided by React Native are combined to build a new component, in this case, the only component, the app component, and how we then get this StyleSheet object, which is used to set various styles which if you take a look at those properties, look similar to what you know from CSS. And then actually this Styles object is provided to this View component through a style prop. But we will take a closer look at styling and at building our own components in general throughout the next minutes and hours, of course. Now, just one final note about this app component: At the moment, this is our only component here. And indeed the app component in the app JS file has a special purpose. This is the root component that is rendered in your app. Expo will automatically take this component, export it in this app JS file, and render this as the root component. So, any other user interface elements and components must go into this app component or into children or descendants of this app component. But again, that is also something we'll explore in greater details soon. - [Maximilian] So let's start by diving deeper into core components like Text and View. And for this I'll actually delete this status bar component and also this import. If I save that, this is updated here on those devices and not much change here, so we don't need this right now. I also will delete this Text component and save that, so that for now we have a blank screen. And now let's try re adding the text like this, "Hello World" between the View, without the surrounding text. If we do that, we notice that we get an error down here. We get an error that "Text strengths must be rendered within a Text component" which is actually a quite helpful error message which tells us in a pretty clear way, what's wrong. And before we fix this, let's also take a look at those devices, those simulators, and here we also get the same error message. And this is actually something important which is why I'm showing this. It's different than what you might know from web development. If you would build a web app, and this would be react for the web and this would maybe be a div instead of a View, then this kind of code would be fine. We could put text inside of a div there. React Native and native platforms to be precise are stricter than that. You can't put a Text into a View which is pretty much the equivalent to a div because it's not meant for that. Instead Views, so the of to divs in the web world, Views are meant to generally build boxes and containers that hold other content. A View could hold some text wrapped into a Text component. It could also hold a TextInput or a button or an image, or anything like this, but you have to put the content into an element that is able to display it. And the View is only able to hold other components, It's not able to display text, and that is something really important to understand. If you wanna display a text, for example, you have to use this Text component and wrap the text opening and closing text around your text. And if you do this and save, then this updates and works again, but that's a first important takeaway even though we can kind of compare those component to HTML. And even though it looks kind of similar, there are important differences. Now, what you will often do when building React Native apps is you will build more complex user interfaces that don't just have one piece of text inside of them. And what's important to understand then is that those different core components have different roles. The Text is a component that's used for, guess what? Displaying text. The View is a component that's meant to hold and lay out other components. Now, we will learn more about laying things out with help of styling in a couple of minutes, but the idea behind the View component is that you typically have multiple child components in there. For example, another text, "Another piece of text". In a Text component, as you learned, but now we got two of them. And we grouped them together in a View just as we might group them together in a div if this would be for the web. Now, in the web, we also have other components like section or article, here in React Native world, it's just the View. This is our container component that we use for holding our components. And of course, those other components also can be nested. We could have another View which actually holds this inner text. So this is all something that's totally fine, something you will typically build when building more complex user interfaces with React Native. The View then makes it very easy to use styling into which we'll dive in a second to control where which of its child elements should be positioned. Of course, we don't just have a View and Text to though. If you take a look at the official website, the official React Native documentation site you'll learn that there are more React Native core components and those components fulfill different purposes. We got View and Text, which are two of the most important and commonly used components, but we also could display a image, add some scrolling, something will do later as well, or add a TextInput which allows users to enter some text. We could also add a button, and indeed, that is what I'll do here. Below this text, I'll add a button, but for this, we need to import it. And that is also important and an important difference compared to react for the web. With react for the web, you don't need to import the HTL elements you might be using, with React Native, you do. If you wanna display a button, you have to import this core component from React Native, and then you can add your button. And number important difference is that unlike for the web, you don't build a button like this by adding the caption between the opening and closing tags. Instead, it's a self-closing element where you add a title prop, and then you add your title here. This would now display a button as well with the kind of default styling and tap effects you would expect for the different platforms. And you see that the look adjusts to the underlying platform. It looks like an iOS button on iOS, and like an Android button on Android. But of course the button doesn't do anything yet because I have added any listener. Now, we will add interactivity, and learn how that works later. For the moment, let's just add the button here and let's understand that we always work with core components like this where every component has its clearly defined purpose, and you build your overall UI by combining those components. But of course a UI is not just about combining components, it's also about styling them, and that's therefore what will explore next. - [Instructor] So let's dive into styling. And here you learned before that there is no CSS support in the React Native, so we don't add CSS files or use the CSS language in general, but you learned that we have two main ways of adding styling by either adding styles in line, by passing a style object to props or by defining a separate object which is then also passed through props. Now we do define our styles in JavaScript then but the JavaScript properties we can set are inspired by the CSS language though it's only a subset of the properties and features supported by CSS and not all the names are exactly the same, as you will see. But let's now see how styles can be applied. For that, we can use the style prop, which is not supported on all elements, but on some elements, for example on the view, but also on the text. For example, here on let's say this text here, we can add the style prop. And then as a value, you can pass a JavaScript object. And in this object you can set all the supported style properties and React Native decides which properties are supported. And these are the properties that are similar to the CSS properties, but not exactly the same. For example, here on this text, we could add a margin. And as you see, as I start typing, we get this nice auto completion here in VS Code. We get this automatically because VS Code understands which kind of properties can be set on this object that is passed to the style prop. Now, here we could add a margin either in one specific direction or in multiple directions by combining multiple properties or in all directions by setting margin. Now different style properties need different kinds of values. And you will see many examples and learn which kind of value goes into which style property throughout this course. Margin, for example, typically wants a number and this number will then be translated to pixels which are automatically adjusted to the device pixel density. For example, here we could enter 16 to have a margin of 16 pixels. If we save this, we got some spacing around this. Now it's not super good to see because we don't know exactly where the text box ends. To make this a bit more visible, we could add a border. Now in Vanilla CSS, you could add a border, like this for example. This would add a red border with one pixel width around an element in Vanilla CSS. But if I type this kind of code and saved this here in React Native, we actually got no effect here, and I got a error here in the terminal and a warning here on my simulator. We can click on this to get more details and we see that this is an invalid value for border. Actually the key border already is invalid. So it's not even the value but border is not a supported key. The reason for this is simply that this border property doesn't exist. I mentioned that the styling language is inspired by CSS and close to CSS, but it's not exactly the same. Instead, as we type border, we see that various properties exist, which we can set. For example, we can set a border with property and this again wants a number to set a certain border width in pixels, like one, one pixel, or two or whatever you want. And then we can also set a bordered color. Now this does not want a number, but instead of string, and in this string, you could define a hex code value Or you provide one of the supported shortcuts like red or blue or green or black and white. And here I will go for red. And this will now add a two pixel, white, red border around this text. Now I'll press the auto format shortcut to make this a bit easier to read and then save this. And with this, we now got a border around this text. The border is pretty close to the text but thankfully we can also add some padding, padding just as in the browser, is the spacing inside of an element. So here we could add a padding of let's say 16 again, 16 pixels, just as for the margin. And if we save this and auto format again to improve readability, now we got some internal spacing. Now definitely feel free to play around more with those style properties. And of course also take a look at the official docs to learn more about styling if you want to, but you will see plenty of styling examples throughout the course. These style properties were all about styling the element itself that holds a certain piece of content. We will later also learn about style properties that help us with laying out multiple components and with achieving a certain overall look. But again, that is something we will explore later. For the moment, I wanna leave this in-line styling approach though. This approach of defining the styles in the same line as we define this component. Because whilst this is possible and allowed, it's rarely the best way of adding styling. So typically we should go for a style sheet objects. The reason for this, is that this allows us to clearly separate our JSX code and our styling code and it also makes our styles reusable. If we define styles in line and I want the same styling on this text, I have to copy and paste this, so that I can add my style prop here and add the same styling, and I'll auto format this to make it more readable. So now I had to copy and paste to replicate this style. And that is typically something you wanna avoid. What you should instead do is create a new style sheet object. Or if you already have one, as we have it here, you go to this object and you add a new property. We already have the container property, now on the same level, I'm adding another property. The name is up to you and I'll just name it dummy text. Again, this is totally up to you. What's not up to you is what you set as a value though. The value should be an object, as we see it here for a container. And then in this object, you define your style properties. So here I could now set my margin and so on. So I can set margin 16, border width two and border color, I'll set this to red. And I will all set my padding and the order does not matter. I just group margin and padding together here, since they're both about spacing, but we could also add padding here, and it wouldn't matter. Of course I could have also just copied down my object from up here. Now with such a style object to find down here, we can use it here in our JSX code as this container is being used. It is defined down here, but you can still use it in JSX because this only gets executed after the entire code file has been parsed basically. So here we can now replace this object by referring to styles.dummytext and I get nice auto completion for this as well. And I'll do this here as well. And now, yes, we had to copy the word, dummy text, but of course it's way less to copy. And if we ever adjust the style, for example we changed the color to blue, we don't have to do this in two places because the name didn't change, we just had to do it in one place instead. So if I save this, we now got a blue border. And that's how we use such a style sheet object. Now, why is it a style sheet object? So an object created with help of style sheet create which is a built-in method on this built-in object which is imported from React Native. Well, we could have also created a styles object like this, and set our styles there, but using such a style sheet object has the advantage that we get convenient auto completion as we type our style properties here. And that makes our development life a bit easier. In addition, React Native could potentially optimize style sheet creation and management internally and pick up style sheet objects like this. This is not done right now though, so for the moment, the main reason is the auto completion. But with that, we now learn some important styling basics and some important basics about core components. I would say, as a next step, we should take a closer look at creating layouts and positioning multiple elements because typically you don't just want a couple of centered pieces of text like this. Typically you are going for different layouts and we need to know how we can create such layouts therefore. - [Maximilian] So let's explore how we can build real layouts where we don't just have a bunch of centered texts and buttons. And for this, I will actually clean up my JSX content and I will remove this style prop here on the outer view for the moment and remove all the styling here in this style sheet object but I will keep the style sheet object. And now here in my view, I actually wanna add a neverview and below that a neverview. Now I'm doing this because I wanna start building a basic interface here that allows us to manage goals. And the first view, the first nested view here I should say, should actually hold the input area where users can enter the text for their goal and click a button to add that goal. And the second view should later hold the list of goals that are rendered. And I'm using two views as rappers to have a clear separation between these two areas, and because data will help me with styling. So for this, I'll then therefore start by adding a text input component here in the first view. This is a component that allows users to enter text and like all components, all core components, we need to import it from react-native. Now text input is a self-closing component. And here we can, for example, add some placeholder text as you could add it to a input element in the web and say, your course goal. Then, next to it I want to add a button with the title of add goal. And then here in this view, I will add a text element where I say, list of goals and later this will become a real list. Now, if we save all of that, we see that everything is crunched here at the top. We also see that it goes beneath the status bar and there would be different ways of fixing this. For the moment, I'll fix it by giving this outer view a style prop and defining a style, which I'll name, app container. And in there I'll add a padding of, let's say, 50 pixels. And then here we can refer to styles.appContainer to add to this padding to the overall outer view. Now, if you save this, we can see that there's more space around our UI. Again, later, we will learn about different ways of making sure that we don't interfere with those native status bars and so on. Now, still, this is not the layout I want. For example, I want the button to be next to this input, not beneath it. I also want to have more space between the list of goals and maybe this area where we add a goal should take up a quarter of the overall height and the list should take up the rest. And that's where we need new styling features. Styling properties about which we haven't learned before. Specifically, we need flex box. - [Instructor] When it comes to building layouts in React Native apps, Flexbox is super important. And you might know Flexbox from the web and CSS. And then the next lecture, will have a little deep dive into Flexbox and how to use it. But Flexbox is a key approach, a key concept which is basically a collection of CSS properties that you use to control how things look like. And the Flexbox implemented here in React Native, which can be set with all those React Native properties, is very similar to what you know from CSS Flexbox. In the end Flexbox is all about a couple of CSS properties, or a couple of styling properties to be precise here, that are about positioning elements inside of containers. You can control how much space certain elements take up, and if they are to the left or right, or bottom or top of other elements. And the positioning is then controlled with the style settings that you apply to the container that holds other elements, as you will see in a second. Now Flexbox is all about Q-axis which you have on a container. For example, the styles which you see here at the top, flex one, flex-direction: column, and so on, would be applied to the container that holds the three boxes inside of it. Now the flex one instruction here, for example, would tell the container that it should expand to occupy all available space, though as you will see soon, this is seen in relation to other containers that might also take up space. And then flex-direction controls whether the elements are laid out in a column as you see it here, or in a row as you see it here. So that all works. Basically, flex-direction controls if the main axis, as it's called, is top to bottom or left to right. With column, it's top to bottom, with row, it's left to right. And then you also got other properties like justify-content or align items that allow you to control how the elements are laid out in their axis. So if there is some space between them, if there are crunched together and so on. - [Teacher] So back in our code, this means that we can use flex box on this view, which is the container of text input and button, to control how these two elements are positioned, because you learned flex box is a concept that is applied to container elements to control how much space the container takes up. That's something we'll do in a second. And then how the elements inside of the container are positioned. That is what we'll do right now. For this, I'll add a number, style property here in my style sheet object, and I will name it Input Container. Now on this element, we can now set flex direction to row, and then we can apply this input container styling to this view. So here we add the style prop, and then refer to styles dot input container. If we save that, you will see the button is now next to the input element. So this already utilizes flex box because by default flex box is enabled on all those views. You can start using those flex properties right away. The default setting was that flex direction was column, which is why the elements were beneath each other. But if we switched to row, as I just did, they sit next to each other in the same row, which hopefully makes sense. Now we might want to control how they are laid out, and for this, we can add another property to the input container, and that is the justify content property. You will learn more about all these flex box properties in depth in the next lecture, but justify content basically controls how these elements are distributed in the row or column depending on what the value here is that they are part of. So here, for example, space between is one of the allowed values, and as you set this to space between, you see there now is more space between these elements. Now we can also still control the width of those elements. For example, here, we could add a text input style object in our style sheet object, and I will add this to the text input here. And here I then wanna add a border with a width of one and a border color of CCCCCC, which is a light gray. By the way, I get a color picker here because of an extra extension, which I installed. You don't need that though. And now, in addition, I will give this text input a width of, let's say, 80%. And this is all the new. Now in most places where you can set a size as pixels, so as numbers, you can also set sizes in percentage, though you need to wrap that in quotes so you set a string in the end. But then you add the percentage sign and your percentage number to set a certain percentage. And with this, I'm saying that I want this element, which has this style, to take up 80% off the available width. The available width will be defined by the container in which the element sits, but then the element which receives this style will take 80% of that container's width. So therefore, now I want to add this text input style here on this text input element, and we do this by adding the style prop and then its styles, text input. If we do this and save that, now we got this border, and this looks like 80% width. Maybe we also want a little bit of margin to the right so that there is some spacing here. There is no spacing right now, despite having space between, because this takes 80% of the width and the button automatically takes the rest. And therefore to add some spacing here, we'll add a margin to the right on the text input of, let's say, eight pixels. With that, there is some spacing again. We could also add a little bit of padding maybe so that the text isn't directly on the edge. So, therefore, I'll also add padding eight here on the text input object. So with that, we get some padding as well. Now that's it for this basic introduction to flex box. This is an not all we'll do. This is not the finished layout. I do see that the spacing is a bit off here on the right and the left. I do see that the button doesn't look that great here on Android. And we will work on this, but first let's dive a little bit deeper into flex box and the different things we can do with it before we then continue working on this app. - [Maximilian] In this lecture, I wanna dive a bit deeper into Flexbox especially regarding how you use it in React Native apps. If you know all about that already, you can of course skip this lecture. So for this, I prepared a simple dummy application and of course, you find data attached. It's a normal React Native app built with Expo. And in the App.js file here, what I have in the end, is just a view with three views in there where each view then has a text with text one, two, three. This simply creates some boxes with different colors, red, blue, and green. And now we'll use Flexbox to move these boxes around so that you can get a feeling for how Flexbox works, because it's so important. Now, first things first, by default, every view in React Native, even if you assign no special styles, uses Flexbox. And that's different to the web, for example. There, if you have a div, which would be your equivalent to a view kind of, it doesn't use Flexbox by default. In React Native, it does. Every view by default organizes its children with the help of this Flexbox thing. Flexbox simply is, is a term, It's simply a concept from CSS that is all about organizing child elements in a one dimensional space. So here, for example, in a column. That's also in every default, not only does every view by default you use Flexbox, it also by default organizes children in a column, so from top to bottom. That's all the difference to the web and I don't wanna emphasize these differences too much because of course you don't need to be a web developer to build React Native apps. But I think a lot of people do know web development, do know a CSS Flexbox, and therefore it makes sense to all the talk about the differences. So in the web, when you use Flexbox not only is it not turned on by default, in addition if you do turn it on, the default is to organize all child elements in a row. And here, the default is to organize them in a column. You can change that default though. So in this case, on the view, which holds my boxes by adding flexDirection here, and setting this to row, for example. Now, you will see that these three boxes are organized in a row from left to right. Now besides row and column, you also have row reverse and column reverse. And this simply also, well does what the name implies, now we still have a row, but the first element, the red box, actually is on the right and not on the left anymore. So that's also something you can do. Let me go back to row view. So that's the first thing you can do. Another important thing about Flexbox is how child elements are sized. Here, I gave every child element a width and a height of 100. Now, if we would remove that width and height thing on every child element, then you will see that now we have a very, very small row here because every box now is only as wide as its child requires it to be. And only as tall as its child requires it to be. So every box here which holds a number is only as wide and tall as the number it's containing. Now, you can change that with the surrounding Flexbox container 2. Let's give that width of let's say 300 pixels or of 80% of the parent width. So in this case, since it's the root element of the device width, and let's give it a height of, let's say 300. If we do that, and now really important, I'm doing this on the view, which holds all these boxes. I'm not doing it on the boxes themselves. So if we assign this width and height on the surrounding box, you see something interesting. The height is assumed for all the elements. Now, all the views in the Flexbox take the height of the parent. The width has no impact here. That's also a default behavior you got here, obviously since we haven't changed anything. The default behavior here indeed, is that the child elements in a Flexbox, so in this outer view here, are organized such that they align themselves along the cross axis by stretching. Okay, that were a lot of terms, what does this mean? Now, when working with Flexbox, we have two important axis. The main axis depends on your flex direction. For row, which we have here, flex direction row. the main axis is from left to right. For a row reverse, it would be right to left. For column, it would be top to bottom and for column reverse it would be bottom to top. So that's the main axis. And then you also have a cross axis and that's simply the opposite of the main axis. So for a row where the main axis is from left to right the cross axis would be from top to bottom. If the main axis is from right to left which would be the case for row reverse then the cross axis would be from bottom to top. Okay, so that's the main axis and cross axis concept. Now, you can organize your child elements. So in this view where we have the free boxes as child elements, you can organize these child elements along these axis. You use justifyContent to organize elements along the main axis. And you have alignItems to organize elements around the cross axis. Now you see the values you got for justifyContent here. If you add these quotes or if you place your cursor in there and you hit control+space. You see you can center elements, you can position them at the end or at the start of that container or you can add some space in between. For example, if we use space between here and we use alignItems center, then things will change. Now, you will see they're taking the width of the surrounding container, every box itself still is pretty small but they're split or they're distributed across the width of the parent container. And they're no longer taking the height because along the cross axis, we're aligning them with align items. And there I set this to center. The default here is stretch. And if I set it back to stretch, then unsurprisingly they do stretch for the entire height. Now, if you want to make sure that they take the available width, you can set stretch here on justify content which is your main axis positioning vehicle. So you can set stretch here. So what can you do regarding that then? Well, that is something you now configure on every child item itself. You can tell a child item how much space it should take off the space it's potentially getting. Stretch here is kind of a special case, there you set this up on the parent item. Normally, you set this up on the child item. So for example, if I set this to center now so that the parent doesn't tell the child how much space it should take. then we can fully control the space a child takes by going to the child style. And there you can add flex, the flex property. The flex property is applied to items that are inside of a Flexbox, so that are inside of a view in this case here. And that can be a view itself but that could also be another component like a text, for example. So now here you can add flex and you can set this to a value of one, for example. So flex needs to be a number. If you set this to one, what you will see is that now the red container where I did set flex to one, takes all the available width it can get just so much that it leaves enough space for the blue and the green container so that they can squeeze their content into the surrounding Flexbox. Now, we can't see the boundaries of the surrounding container but the boundaries would essentially be where the red item starts and the green item ends on the horizontal axis here. So now flex 1 makes sure that the red item gets as big as it can get, So it takes as much space as it can get. but default views only take as much space as their child elements require. So as this one character required, but with flex one you change this and they now take as much space along the main axis. So along the width here, as they can get. For the cross axis, again, that's a special case, You have to do this on the parent. For the main axis, and since we have row here, the main axis is a horizontal axis from left to right, you do this with the flex property on a child. Now, of course you can add flex to other child elements as well. Like to the second, to the blue container, with the two in there. You can add flex 1 there as well. So now I have flex 1 on the red container and flex 1 on the blue container. And what now happens is that both of them take the available free space, and amongst these two boxes, the space is distributed evenly. And that's what this number here indicates. This number is a relative number. All items in the same Flexbox with the flex property distribute the available space by considering the number you assign here. And these numbers are relative to each other, so if I give the blue container flex 2 here, then this means that of the available space you have in that surrounding container. After deducting the space, every element needs to squeeze its content in there. The blue container will take twice as much space as this one, because here we have flex 1, here we have flex 2. If we had flex 3 here, then this would take three fifths of the available free space, because we have three plus two, so we have five available segments, so to say. And here the red container would take three segments, blue container would take two segments. If we have one and two, then we have three available segments, and the blue container takes two of them, red takes one. So you always add up these flex numbers and then distribute or that's automatically done, of course but then the available space is distributed accordingly. So now here we'll see that the blue container is twice as big as the red one or it takes twice as much free space as the red one. So this is how you can work with flex. You can organize how items are positioned with flex-direction, with justify content and with align items. And you can also make your items grow and shrink the help of flex. So now that's our brief introduction to Flexbox in React Native. As I said, inspired by Flexbox for CSS. So if you knew that, all of what I explained here is probably not new to you. We'll work with Flexbox throughout this course, so there're things also will become clearer and we'll work a lot with it. And you'll see you how you can create beautiful user interfaces with Flexbox. Flexbox in the end is the tool in React Native to structure your content on a page, to organize your content. And you would typically work with a lot of views which you also nest into each other so that you can position elements the way you want. Because of course, and that's also important, you don't just have to have one view in your app which uses Flexbox. You could have another view in there which also uses Flexbox. And actually, as I mentioned every view by default uses Flexbox and you can then nest these views into each other so that you position everything the way you want. And you'll also see this in this module already. And actually I'm already doing it here in my views here which are in the surrounding view. So my boxes here, there I also use justifyContent and alignItems to center my numbers in these boxes. So that one, two and three are centered there horizontally and vertically. And that works because we have Flexbox turned on by default and we can't turn it off by the way. And therefore, I just use these two properties here to align my content of this view along the main and the cross axis. And here, since I have set no special flex direction for this view, the main axis is top to bottom because the default flex direction is column and the cross axis is left to right. That's just a side note. - [Instructor] So now after this deep dive, let's use our newly gained knowledge to improve this overall layout. One thing I will do for example, is work on this app container padding. This actually doesn't use any of the new knowledge but I need to do this to make this look a bit prettier. I basically just want to have a padding to the top of 50 and then I wanna have a padding horizontal, so left and right of 16. So not of 50 but of 16. With that I'd say, this generally looks better, though we can see that this padding is kind of ignored and our button here is going off the screen. This can be fixed by decreasing the amount of width our text input has to 70% maybe. Now this looks better. What doesn't look better though is where this text is in this button. This is something we can improve with align items on the input container though. At the moment, the problem is that basically this button is stretched to be as high as this text input. And the text is then not centered in the button because the button doesn't have any styles that would center the text. Now you could think that maybe we can add some styling to the button but it turned out that the button is a component that doesn't have a style prop. It might look like it has because I'm getting some auto completion here but that's actually only some auto completion I get here because I typed the word style before in this code file. The proper auto completion that tells me that a certain prop is supported looks like this with this kind of icon next to it. So the button doesn't have a style prop because indeed it doesn't support styling. You can always check out the official docs and dive into an element there to see which props it supports. And for example, on the button, there is no style prop. Whereas on the view, for example, you do find a style prop. But that's just a side note, that's why we have to fix it differently and we can fix it by not stretching this button. That would be one way of achieving this. So we can set a line items here on input container and set this to center instead of stretch. With that, the button is now centered and looks better. We could also build our own button but that is something you will learn later. So now this looks better. I also wanna change how much space this input area takes up though and how much space the list of goals takes up. To achieve this, I'll do a couple of things. For example, I wanna add some padding to the bottom on this input container of let's say 24. so that there is some space between the view that holds the text input and the button and the view that will hold the list of goals later. You can see that spacing here now. We also could add a little border here, so we could add a border to the bottom and give it a width by setting border bottom width of one. And then adding a border to the bottom and giving it a color of let's say, maybe this gray again. But of course you can pick any color you want. Now we got this border and below that to the list of goals. But now I want to make sure that my text input area takes up one fourth, so 1/4 of the overall available height. And this can be done with the flex property as you learned. We can set this to one and then add a styling object to this view that holds the list of goals that takes up three quarters of the available space, which can be achieved by adding flex three to this view. So therefore I'll add another styling object in my style sheet here and name it, the goals container. And here I'll set flex three. As you learned, all the flex values are added together as long as the containers to which they are added are siblings to each other and are part of the same surrounding parent element which is the case for these two views and then the space is distributed accordingly. So one plus three is four and therefore this takes one fourth and this will take three quarters. We just have to add this here, so I will add a style prop to this view and set this equal to styles goals container. With that, it will look horrible. And the reason for this is that we also need to work on the outer container now. The container that holds these two containers on which we just set the flex properties. This outer container needs to take up the entire height of the app so that the inner containers can then distribute this space. By default, without the flex property, this container will only take as much space as it needs and that's only defined by the space the content in the container takes up. But now that we're setting flex on those containers in the container, this doesn't work anymore. And to fix this, we need to force this container to take all the available height and we do this by simply adding flex one to the app container so that the outer container takes all the height because it's the only container here. So flex one will give it all the space and then the inner containers can divide that available space. So by adding flex one to the app container and saving this, this now looks better. And now this is a quarter and that here are three quarters. Now if I look at it like this, this still doesn't look perfect so what we might wanna do is actually give that list here 4/5 of the available space, so that goals container will get four and the input container stays at one. And instead of setting a padding bottom, I will set a margin bottom here on the input container. And with that, that looks better. We could maybe even go to flex five down there and leave it like this. Feel free to experiment with this and choose your own values. But this will work for me and this is now flex box in action to achieve a first basic layout. Of course, this is not the final layout we will have though. - [Instructor] So we did add some styling and a basic layout. This is nice, but of course, not all we wanna do. In most apps, no matter if we're talking about web apps or native mobile apps, we also want to allow the user to interact with the app. And we got a text input here and we also got a button that could be pressed, but at the moment, of course, nothing happens if you type here or if you press this button, this is ignored. And this is ignored because we're not handling these events. And just as with a web app that you're building with React, you, of course, need to handle them if you want something to happen. The good news is that you do handle events in the same way you would do it in web apps though. You can add event listeners and connect them to event handler functions and you can manage state in your components with the useState Hook, just as you would do it in any other React app. Because this is just a React app, the only difference, as you learned in the first course section, compared to a React app that targets the web is that we use a different platform with React Native instead of React DOM. But when it comes to React's core features like handling events or managing state, that all works in exactly the same way as you know it from React for the web. And here I got two events that I wanna handle. The first one would be a click on this button but before we handle that I also wanna handle keystrokes on that TextInput element so that I can grab the value the user entered and so that we can then use this value to finally add a new goal in this list of goals as a next step. And therefore, these are the first two things I wanna do. I will add a function that could be called goalInputHandler that is responsible for fetching that user input as the user types. Then I'll another function addGoalHandler which should be fired when this button here is clicked. Now to connect those functions, we use special event listening props that are provided by React Native on its components. For example, to connect goalInputHandler to TextInput, we can add the special onChangeText prop. This is a prop exposed by React Native which wants a function as a value, a pointer at a function. In my case, I'll point at this goalInputHandler function. So I'll pass that as a value here and I'll press the auto format shortcut to make this a bit easier to read. Now, please note that I don't execute this function here. I don't add parentheses. If you would add parentheses this function would be executed as soon as this code is parsed and evaluated. And this would be too soon, because that would be the case when this user interface is rendered. I don't wanna do that. Instead, I wanna point at this function so that React can execute it for me whenever this text changes in this input and that's what will happen if we set it up like this. Now in this goalInputHandler function here, we then receive the entered value automatically because keep in mind, it will be React that calls this function because it's React Native that exposes this prop. And therefore, React, or to be precise React Native, will also provide us a value as a input as a parameter to this function and that will be the enteredText. So we get the enteredText automatically. And then we could, for example, console.log this here. Like this. If we save this code and we have the npm-start process up and running, we can go back here. And for example, enter Test. And as I type this here, you see the log update here in my terminal with every keystroke until we have the word Test. So that's how this works and this works totally on its own. So that's how we can get the entered value. Of course, we don't want to get the value because we need it in this function though. Instead, we need it in this function. So we need it when the button is clicked. And for this, we need to connect this function to a button click as a first step. Now, if you would be building a web app and you had a HTML button here, you would add the onClick prop but with React Native, this prop doesn't exist on a button. But we have a similar prop, it's called onPress. It's called onPress instead of onClick because technically we don't have clicks in native mobile apps. Instead, we have taps or presses. So here we have onPress. And just as with onChangeText, here I point at my function that should be executed. In this case, addGoalHandler. So now this function will be triggered whenever the button is clicked or tapped. Now we want the value entered in this TextInput in this function. So what we need to do is we need to store it as state. We need to store it as state which is updated with every keystroke in this function so that we can then use it in this second function. And state management works just as it works in any other React app. We can import the useState Hook from React. So not from React Native, but from React: the core React library itself. And then we can register a new state here in our App component function just as we do it in any other React app. So here I'll call useState and set this to an empty string initially, because this will be my user input state or my enteredGoalText state, which can be updated with the setEnteredGoalText function. And then in case this syntax doesn't tell you anything, definitely have a look at some dedicated React resources like my React complete guide course because this is standard React and you should know syntax like this. So now we got this enteredGoalText state, which initially is an empty string, but with every keystroke in my TextInput, I will update it and set my enteredGoalText to the enteredText I'm receiving here as a parameter. And therefore, now, in addGoalHandler, we can access this state and do something with it. And for the moment, I will simply console.log my enteredGoalText state here. But of course, soon, we will update a list of goals which we then output down there. So let's save this. And now here, if I enter Test and click Add Goal, we got this Test log here. Or if we enter Some other text! to see that this is really coming from our updated code. Now we see Some other text!, here. So this is working as intended. The next step now is to make sure that we can manage a list of goals, which we then can also output. - [Maximilian] So let's now manage that list of goals. For this I will again add some state here because my list of goals is also some data that changes dynamically and as it changes, the UI should be updated. And that's a typical case for using state. And this state will be initialized with an empty array because I wanna manage a list of goals and initially I have no goal. Now I'll give this state a name of course, goals, because these are my goals for this course, let's say. And to set course goals, updating function. And now in add goal handler, instead of logging our entered text to the console, we can call set course goal and update our goals. And in the end I wanna take my existing goals and append a new one. Now, there are various ways of doing that. One way would be to create a new array and use the spread operator, these three dots, which is standard JavaScript code, modern JavaScript code, to spread existing course goals into this new array, so that I keep all the existing course goals. And then I add my new goal, by adding the entered goal text, let's say, as a new goal. In this case, a goal is simply a string. We could do this, but if you followed a good React resource, like my course or the official docs, then you know that this is not the best way of updating state if your new state depends on the previous state. Which this state here does. If your new state depends on the previous state, a better way of updating is to pass a function to this state updating function, a function which will be called automatically by React Q then derive the new state. And this function will automatically receive the existing state by React. So here we could turn this into an arrow function that gets the current course goals as a input, let's say. So as a parameter. And again, the value for this parameter will be provided automatically by React when it calls this updating function or this function that's passed to the updating function, to be precise. And now this value, current core goals, can be used inside this arrow function body. And now we do derive this new state in a better way. The other approach would've worked as well but this is a recommended way, a best practice way of updating your state. So now we're updating this course goal state based on the old course goals by appending a new goal. The next step of course is to now output the list of goals here. And how does this work? Well, it works basically as it does in React for the web as well. We have an array of values which we wanna output and in React for the web we would use the map method, typically, to map our array of data, of strings, or objects, into an array of JSX elements which can then be output in the JSX code returned by this component. And we can do the same thing here. Instead of outputting this dummy text down there, I want to output something dynamic, which we do by adding curly braces, opening and closing. We can now refer to the course goals array, and call the map method on it. A standard JavaScript method because we are writing standard JavaScript code here. As you learned. Now, this map method receives a function, as it always does, and here I'll pass in an arrow function, which as an argument, as a parameter, gets the individual values stored in course goals, so my goals here, the single goals I have in this array of goals, this function is called for every item in the array. So every function called receives a single goal. And then as a return value in this arrow function, we returned a JSX element that should be rendered for the individual goal. And in this case, I wanna output the goal text. So here I will render a text JSX element, and then between the opening and closing text I output goal. Since my goals are just strings here in this array because I just add my entered goal text, which is just the text that was provided, and therefore just a string, I can simply output the goal between those text like this because goal will just be a string. And with that, if we save this and we give this a try here. Learn React Native. If I click add goal, this is added but we also get a warning here. The same will be true on the iPhone here. If I learn React Native, it works. If I learn it with multiple exclamation marks I still see that it works. I add another goal now as expected but we get a warning here. We get a warning that each child in a list should have a unique key prop. And this is actually a warning you might know from React for the web as well, because this is a warning that has nothing to do with React Native. Instead with React in general, when outputting a list of data, as we're doing it here, every item in that list should receive a key prop which uniquely identifies the individual list item. Under the hood this helps React update the list in an efficient way, so to say. I do explain this in greater detail in my React course, but you should always add this key prop to the individual items that you're outputting as part of a list. Now, the value you pass to key can be anything but it should be something unique that uniquely identifies the concrete value that you're outputting here. In this case, I'm just outputting goals, which are just strings, so I'll take the goal string itself. This is actually not necessarily unique because I could enter the exact same goal text twice but it's good enough for now, we'll improve this soon. Now with this key prop added here though. Now, if I add another goal, I don't get the warning again. And of course here, we don't have to enter the same text all the time. We can also learn different pieces of text, like learn all the details, and as you see, our list keeps on growing here. So with that, we're now able to handle the user input, store it and React to a tap on this button. And then we do something which you certainly did many times with React for the web. We're outputting that data here in a list, but that's of course not all we want to do. - [Maximilian] Outputting the data in a list as we're doing it here is nice but it would also be nice to have some styling on those list items. And therefore, that's what I wanna do next, of course feel free to also pause the video here and practice this on your own. Apply some styling, any styling of your choice to these individual list items, and then compare your solution to mine to see how I style this. Now, here's what I will do. I will create a new object that keeps or that holds the styles for those list items. And I'll name it, goal item. The name is up to you though, here in this style sheet object, and then in this object which defines the styles for this identifier, you can set up any styles you want, and I'll give every goal item a little bit of margin, for example so that we have some spacing around it, maybe eight pixels. I also wanna add a border radius here so that we have rounded corners and this also wants a value, that's defined as a number. And here I'll set this to six pixels. Now to make sure that we can see this radius, I will give this a background color so that this item has an overall background color of a specific hex code that I prepared ahead of time which is five E zero A C C, which is a nice purple color. I also wanna have some padding in here so I'll actually add it next to the margin not because it's required but to keep those related values together. And I'll add a padding of, let's say eight pixels as well. So that we have some inner spacing as well. And last but not least, I also want to add a color here and I'll set this to white and this will be the text color. So again, you see the property names are pretty similar to what you know from CSS. We of course have this camel casing instead of using dashes because dashes are not supported in JavaScript but besides that, the names should look familiar. Now we can assign this goal item style to our text items here. So here we can add the style prop and set this equal to styles.goalItem. And I'll reformat this to make it a bit easier to read. With that, if we save this, this updates and we see our items here. What you will see is that we got this changed styling but actually on iOS, the rounded corners are missing. We only have them on Android. Now, why are they missing here? And what can we do to fix the styling there as well? This is a good time to talk about the differences between the two platforms. The idea behind React Native is that you can write code with React that will actually give you native mobile apps for multiple target platforms. So you don't need to write different code to target different platforms, but one of the same code base can get you there. Now this is generally true, but as you will also learn later in the course, sometimes there are differences and sometimes you need to make tiny code adjustments to target all platforms in the right way. And for example, here, we got a difference. The rounded corners are missing on iOS because we added our styling here that applies the rounded corners directly on this text component. Now it turns out that this text component is translated by React Native to a fitting native widget, a native UI element. And the element to which it is translated in case of Android seems to be an element where corners can be rounded. But in case of iOS, it looks like the underlying native text output element does not support rounded corners. And that's why border radius has no effect on the text elements on iOS. Now to work around that, we can wrap our text here in a view. So in this more generic container element, this is also translated to a fitting underlying element. And it turns out that the underlying element to which view is compiled by React Native is an element that supports surrounded corners on both platforms. How do I know that? From the official docs and experience and I'm explaining it to you in this course so that you don't have to find it out the hard way. So what we can do now is we can grab our style assignment here and add this on this view and also add the key here on this view, because now the view is the main element that's output here in the list. The text now is a nested element. We still need the text because we still have some text to output. And as you learned before, text must go between text text but the styling is now applied to the more versatile view element. If we do that and we save everything we now see the rounded corners on iOS as well. What we also see though is that the text is no longer white. Now we still have the color white setting here but this is part of the goal item, which now is actually assigned to this view here, not to the text and unlike in CSS for the web, the styles don't cascade. That's another important learning here. We do have this CSS like property language here if you wanna call it like that, these CSS like property names, but it's not CSS. It never was. So therefore core CSS characteristics like the cascading nature of CSS, where child elements and descendant elements, inherit styles from parent and ancestor elements is not part of React Native's styling approach. We don't have style inheritance here. So if we assign a text color to the view, this does not affect this text or the text inside this text text to be precise because that's a totally standalone element. It is not related to this view. It does not inherit any styles from that view. So setting the text color on this view does nothing to the text inside that text element. Therefore, what we need to do is add another style object here, the goal text, that sounds like a fitting name. And we set our text color on that and remove it from goal item on the view. We could leave it there, but it doesn't have any effect, anyways. With that, we now set our text color here and now we can add this goal text style to this text here. So we add the style prop and set this equal to styles.goalText. And with this, if we save this now, we now have the white text back and we have the rounded corners. And this is really important. This is something you must understand about styling and about targeting different platforms. The general idea is that you have one code base that targets both platforms but still there are differences under the hood. And some differences can simply be solved like this by adding an extra wrapper. Later in the course, you will also learn that sometimes you need to write totally different code for different platforms and you will learn how that works as well. And you also learned that styling is a bit different than in the browser. It looks like CSS, at least a bit but there is no inheritance and no cascading going on. That's why you really have to set the styles on the elements where they are supported instead of some global parent element, just as the rounded corners couldn't be applied to the text, the text color applied to this view didn't have any effect to the internal text here. We need to set that on the appropriate text element. And these are these tiny details, which you will see over and over again throughout this course and which are super important when you are working with React Native. But with this, we now got the look we want here and hence, we can now move on and dive a bit deeper into how we can and should output lists like this. - [Maximilian] So we got our list here. Now, one thing you will notice about this list is that if I add more and more items here and I just add exclamation marks to make them unique, at some point we will go beyond the available space. Now you would expect that you simply scroll now, but it turns out you can't scroll. No matter how you try, this is not scrollable. Because by default the view generated here, this view that holds everything in our app component is not scrollable. That's also a difference compared to the browser. On a website, if you exceed the available space by default scrolling bars will appear, and you can scroll the website. This is not the case here in mobile apps. If you want to scroll, you have to explicitly tell React Native and the native platforms. Now, of course, this is a common problem and scenario though, and, therefore, making lists, or content in general, scrollable, is very easy. There is a dedicated component provided by React Native that helps you. And that's the ScrollView. We import ScrollView from React Native just as we imported text input button and so on. And ScrollView does what the name implies, It gives you a view so such a container element, which will be scrollable. And therefore we can now use this ScrollView around our goals here. So let's try replacing this view here with our ScrollView, simply. We add ScrollView here instead of view around our list of goals. And I leave my style on this ScrollView. Keep in mind this style here controls that this container takes up a lot of space. If we save this, this doesn't look too good. This now is indeed scrollable, as you see, but the space is different than it was before, we have way more space for the input and way less space for the list. The reason for that is that the ScrollView has the job of making something scrollable, but the area that's scrollable is in the end determined by the current, the container that holds the ScrollView. So what you should do here is add another normal view, which restricts the available height, to which you then apply the style that sets the height that will be taken up by that view. So that is the setup we had before, but now we have a ScrollView inside of that view. So the outer view, controls how much space this area of the screen should take up. And the inner ScrollView then makes sure that this space, and the items in that space, to be precise, will be scrollable inside that overall space. That's how we set up such a ScrollView, and how we let it interact with the surrounding container. If we set it up like this and we save everything, we get the same proportions as before, but now, indeed, as you see, this list is scrollable here. And that's, of course, what we want, because now we have a list where we can add more and more items and it stays scrollable as we exceed the available space. Of course, if I force a reload, by pressing R here in the terminal. And I then go back, all the data is lost, and now you see, nothing seems to be scrollable here. If I add a single goal here, we do see, though, that this is indeed scrollable, but of course it's not really scrollable, It always jumps back to the top because we don't exceed the available height. So, ScrollView is super useful because it does allow you to make lists, or content in general, scrollable. Now you can learn more about ScrollView and the props it supports in the official docs. I wanna draw your attention to those props here, because there is a lot you can configure, about the ScrollView. You can, for example, configure how it bounces, and you'll also see that some props are specific to iOS. And others specific to Android, whilst yet others are available for both platforms. And again, these are some of these platform differences, which we will encounter here and then throughout this course. For example, you will notice that in our app here, I can scroll and I have this bouncing effect. If I would want to disable this, I could set always bounce vertical, which is true by default, to false. So if I go to ScrollView, and I set always bounce vertical to false, and I then save this, you will notice that here in iOS, if I now try to scroll, this bouncing effect, which we had before, is gone. Now, if I add more and more goals to make sure that I exceed the available space here, at some point, it still is scrollable, and now it also bounces, but it didn't bounce, if there was not enough content to fill the available space, the available height here. If you do want to set this or not as totally up to you and which look and feel you want, but it is important to be aware of the vast configuration options you have here. And therefore taking a look at those props here, and understanding what you can set and how you can use this view is definitely something I would encourage you to do because every app you're building will be different and every app needs slightly different configuration. And therefore the official docs are always a great place where you can find all kinds of supported configuration settings. - [Maximilian] So we got our scrollable list here, and this is implemented with this ScrollView. Now, this solution has one downside, one disadvantage though. ScrollView is great, if you wanna add scrolling around some content. For example, if you had an article, which would be too long to fit on a screen or you simply don't know which device sizes your users will be using and you wanna make sure that an article for example, is scrollable. In such situations, ScrollView is perfect. For lists as we have it here, it's not perfect though. The reason for that is, that lists like this could become very long. Sure, you might only have like 10 or 20 items on there. And especially for such a goal list, it's very likely that you have around that size or around that amount of items. But you could also have lists with hundreds or thousands of items. Now, what ScrollView does is, it always renders all the items that are inside of it whenever the overall UI is rendered. So even if an item is not currently on the screen like this last list item here, this item is still rendered behind the scenes even though it's not visible yet. Because ScrollView renders all its child items, no matter if we're talking about 10, 20, or 10,000 items. And for very long list, this can become a performance issue. If you have a long list with dozens or hundreds or thousands of items, rendering them all at the beginning even though vast majority is not even visible to the user, will slow down the app. And of course, that's not something we want. Therefore ScrollView is great for limited amounts of content like an article which has a fixed end at some point. But for dynamic lists, which could become super long. We typical don't wanna use ScrollView. We can, but we typically don't want to, to avoid possible performance issues. A better solution for such scenarios is another built-in component that ships with React Native, the FlatList component, this is another component that will help scrolling. But as the name suggests, it's specifically built for scrollable lists. And internally, it will only render the items that are actually visible. And all the items that are off screen will only be loaded and rendered lazily as they are needed because the user is scrolling. Now, internally, FlatList will have a small threshold to make sure it already starts loading and rendering items before they are visible. But it will only render them as the user gets closer to them as he or she is scrolling the list. If you have 1000 items in your list the vast majority of items will not be loaded and will not be rendered when using FlatList. So how do we with FlatList then? Well, you do use it by replacing ScrollView with it. So we replace ScrollView with FlatList. Now, regarding this alwaysBounceVertical prop here, this is still supported. So you can leave it there because FlatList actually supports pretty much all of the props ScrollView supports. Because internally it kind of has a similar implementation but with this optimization of only loading data when it's needed. So this is a first step, but we're not finished yet. We replace ScrollView with FlatList. The next step is that we get rid of our custom mapping code here, we remove that, we no longer map our data manually. Instead, we now have to pass this task to FlatList so that it can render this list efficiently by only rendering what's needed. FlatList is now in charge of this hence we need to let FlatList do that. And this is done by giving FlatList two important props. The first one is the data prop, which is a required prop. This is a prop that points at the data that should be output in this list. In our example here, that would be the courseGoals array. That's the data that should be output as a list so we pass this as a value to data. But that doesn't tell FlatList how the data should be rendered. You don't tell FlatList by passing content like this, between the opening and closing text, that's not how we use FlatList. Instead, we should cut this and we can turn FlatList into a self-closing component. And we add another key prop now, and that's another required prop, the renderItem prop. This is a prop that wants a function as a value, a function that will tell FlatList how to render the individual data items. Therefore it is a function that will receive the individual item as a parameter, automatically. FlatList will pass in this item whenever it calls this function, and it will call this function whenever it determines that a new item must be rendered because the user is scrolling and a new item should be made visible. And therefore, in this function, in this array function which I defined here, you then return to JSX code that should be rendered for a given item. Now, of course, we wanna output our item data and we received this item parameter value automatically by FlatList. But this item which we get here is actually an object generated by FlatList internally. An object that is wrapped around the individual data items we have in our data array. And therefore I will actually name this itemData because it's actually an object that does not just contain our values, but also some metadata. Now, itemData does for example, also give us access to a index property. Again, this object with this property is generated by FlatList. And this holds the index of the different items that are rendered. First item here has an index of zero, the second item has an index of one and so on. But itemData also holds another property that's very important for us and that's the property I will output here, the item property. This will hold the actual data items, one, for each list item that's being rendered. So with itemData.item, we get access to the different data items we have here. Now, with that, we can get rid of this key prop because we're no longer mapping this list manually and hence keys are no longer managed like this. We will come back to keys in a second but for the moment we'll remove it. And now I will reload the apps by pressing R here, in the terminal with the terminal selected. And if I now add another new item here, you will see it shows up and I can add multiple items here. And if I add enough items to exceed this screen height. So if I add more and more items here, you will see that this list also is scrollable, I can scroll here. But you also see of course that I'm getting a warning, I did get it right from the start actually. And the warning is the end, that I'm missing some keys here. Because it's still a list and therefore we still should add keys, but we don't add them as we added them before. Instead when using FlatList, there are two main ways of adding keys to these list items. The first approach is to turn your data values from primitive values like strings as we have it here, into objects that have a key property. And that's what I'll do here. When I add a new courseGoal, instead of just adding the entered text like this as a goal so as a plain string, I will wrap this into a object. Where I, for example have a text property that the actual goal text, but where I actually also add a key property which I set to a unique key. Now, to generate a unique key here, I will actually use Math.random toString like this. Which is not really a unique key. I could generate the same number twice but it's good enough for this demo here. And now with that every item in my course goals array is actually an object, an object with a text property and with a key property. And the special thing is that FlatList will automatically look for such a key property. So FlatList does work with primitive values in the data array as well as you saw a couple of minutes ago. But it works even better, if your data in this data array is a list of objects. So if you have a list of objects as data and every object has a key property, because then this key property will automatically be used as a key for the items that are rendered. Now, that we turned our items into objects here though, we have to make sure that when we access the data that belongs to a single item, we dive into the text property here on the item. Because every item is now an object with a text property, that's what we set up here. Hence we have to access this text property down here. And then with that, if we save this and again reload this and I now start adding items here, you will see that now I can add items as many as I want and I don't get this warning anymore. And I got this strollable list. And under the hood, only the items that are needed are being rendered and the other items will be loaded lazily as we scroll closer to them. That's how this FlatList works now. Now, if you don't have a property named key because you're maybe getting data from an API and you can't influence its shape, and you don't wanna transform it just because flat list needs that key property. You also got an alternative to setting up such a key property in the input data. Let's say this would be named ID, this would be a reasonable property name because this could be a unique ID. But it would be the wrong name because this list is not looking for an ID property but for a key property. Now, of course we could transform it but if you don't wanna do that, you can go to your FlatList and you can add another prop to the FlatList component. And that would be the keyExtractor prop. The keyExtractor prop wants a function as a value, for example, an inline arrow function. But you could also define a function somewhere else and pass up a point or edit here. And this is a function which will automatically receive two parameter values, item and index. These two values will be provided by FlatList when it calls this function for you. And it will call this function for you, for every list item that's being rendered. Now, the renderItem function is also called for every list item that's rendered. But the renderItem function is responsible for generating in the JSX code that should be rendered for every item. KeyExtractor on the other hand, this function is simply called to get a key out of every item, which then under the hood will be attached to the item by the FlatList. And therefore here you should return the key. And since you get the item as the first parameter value, and since I know that every item for me is an object with an ID property. And since I know that the ID property makes for a great key since it will be unique, I can return item.id here. And with that, I simply tell FlatList how it gets to a unique key for every item it outputs. So with that, if I save this and I then again, reload everything here. If I again, learn React Native here, this works as before. And I don't get any warnings. This off course, all the works here on Android if you wanna see it there. I can add multiple goals there as well and there it's also scrollable. So that's FlatList and action, and you should use FlatList whenever you have lists with dynamic data that should be scrollable. And especially if you have lists that could be super long. Then, for performance reasons FlatList is better than ScrollView. - [Maximilian] So by now, we already learned a lot about important React Native components and concepts in general. Our app JS file is getting bigger and bigger. And this is something that happens in most React apps, no matter if you're building for React Native, or if you're building for the web. Your components get bigger as you add more functionality. Now, what do in such cases is you break up your components and you split them into smaller components. That is a common approach and a common best practice for keeping your code maintainable. And it's no difference here for React Native. Thus far we're working with one component only but this of course is the exception. The norm is that you do work with multiple components. And we wanna do that here as well. For this, I'll add a new folder in my project which I'll name "components" because I wanna store my components in there. You don't have to use this name but it is a common convention since we will be building and storing components in there. And then I want to add two components files in there. Goal input JS, because there I plan to store the data input related JSX code and functionality. And goal item JS, here I plan to store the actual JSX code and functionality that is related without putting single goal items. And of course you could split this into more components, if you wanted to. Now I'll start working on this goal item component. In there I'll add a function goal item because I'll create a functional component and I will export this as a default. So I will build a standard React component in there. Now you don't need to import React from React here. You did need to do that in the past but with the modern versions of React Native and React you don't need to do that anymore and therefore a functional component can be created just like this. Now in this goal item component, I wanna return some JSX code and I actually wanna return the code that is responsible for outputting a single goal item. So not the list of items, but a single item. And that means I wanna use this code here. Hence, I will cut this code from app JS and return it here in goal item JS. Now, of course, here, I'm referring to some styles though and those styles therefore also should be brought over. For this I have to create a new style sheet object that belongs to this component. So to this component file also and hence I will import from React Native and I will import the style sheet object here. Which allows me to call the create method, which creates a new React Native managed styling object, which helps with auto completion and so on. I'll store this in a constant named styles, though the name is up to you, but since I'm already referring to this kind of constant here in my code, I will keep the name here. Now as a side note, we could have also passed our styles from app component to goal item component via props. We don't have to define the styles here but it is a good practice to keep your styles close to your JSX code. And therefore I wanna move my styles that belong to the goal item from the app component into the goal item component as well. And that would be these two objects with their style properties. I will cut them in app JS and move them over to goal item JS. And here in this object which we pass to the create method, I'll paste in these two properties. And with that, I can reference those properties in my JSX code. So with that, we are creating this component. We still need to take care about this text, but we get our first component and then app JS we can now import this component. We can now also get rid of some imports which we don't need anymore because I'm, for example, not displaying a text component in there and I'm not using scroll view anymore But I will now import goal item from components goal item. And this works just as it works in our regular React app, we import our components from other files like this, we have a capital starting character because we plan on using this in JSX and we wanna make it clear to React that this is a custom component. Hence we start with a capital character. Now down here in our JSX code, where I return some markup inside of render item. I now return my goal item component, so my own component. And this is how we define and use a custom component. And of course in the end it's totally the same as we do it in a React for web project. There isn't really any difference here. - [Maximilian] Now of course we will need to pass some data to goal item though, because we got the item data here in the app component and we need it here. And this is a problem solved With props. Again, just as we do it in any react app because we are building a regular react app here, we have a regular react component and we can use props therefore. And we can expect and use any props we want, because it's our component. So here for example, we could expect that on this props object, we get a text property, or a value property whatever you want. I will go with text here. And now we just have to make sure that in the place where we use this component, so in the app component here, We pass this prop so that we set a text prop here, on goal item in the app component. And then here we have to pass in item data dot item dot text. Because again, text is the property that holds the actual text and I wanna pass this text as a value to the text prop in my goal item. And with that if we save this and I reload everything, if I go back and I learn React Native here, this crashes. Because of this error, can't find variable view. What's wrong here? Well, what's wrong is that in the goal item component, I'm using the view and the text components but I'm not importing them. And I showed this on purpose, because this is important to understand. If you are working with a react for the WAP, you can use DVs and h2 elements just like this. You don't need to import them. That's different in React Native. There, all these components are provided by react native, and you have to import them in order to use them. So besides importing the style sheet here, we also have to import view and text, because we are using these two components in this JSX code. And once we import them, if we now reload our apps again, you will see that now of course if I do learn React Native, this works again. And now it's looking the same way as before, Because in the end we get the same UI as before, but we're achieving this with help of another custom component. - [Maximilian] So now we got this custom component. But we got another custom component, which I wanna build. And this component should hold the input related markup and logic. Now, definitely feel free to extract the appropriate code from App.js into GoalInput.js on your own and build your own GoalInput component, which you use in App.js. In a couple of seconds, which I give you to pause the video. We will do this together. So, did you succeed? Let's try this together. Now here, I want to extract some markup into GoalInput. For this, I'll First of all, create a GoalInput component here, in the GoalInput.js file and export this. and then we wanna return some JSX code in here. The JSX code that should be returned is the TextInput and the Button, but I will also grab the View that holds these elements as the container, Because that View holds the input related container styling. And I wanna outsource this well. So here, I will add this container with the TextInput and the Button to my GoalInput.js file. Now, just as before, we need to do a couple of things. We need to import View, TextInput, and Button and we need to bring over our style sheet objects. Now, I'll start by importing, and I will import View, TextInput, and Button from react-native, so that we can use these components here. And it will also import StyleSheet, because, of course, I will create a style sheet. I will create such a styles object here with StyleSheet.create, so that we can set up the styles that belong to this component in this component file. And in our case, that would be the inputContainer and TextInput styles. So in App.js here, I will grab the inputContainer and TextInput style objects, and cut them, so that our style definitions in App.js are now much leaner. And it will move them over into the GoalInput component file. So here in this object, I'll now paste them in, and that makes sure our styles are there. But now we're not done. We also are handling some state here. We're getting the user input and we're interacting with the main courseGoals state with help of this Button. But now the problem, of course, is that the courseGoals state is managed in the App component, whereas, the inputs are in a different component. But that's a common problem in react apps and not specific to react-native, and we can solve it as we solve it in all react apps. We can also talk to the parent component by passing event handler functions via props. So here, for example, we can accept props on GoalInput and expect a special prop which could be named, onAddGoal, to be provided by the parent component, which actually holds a function as a value that will be executed upon a press. So now in the App component, we can use the GoalInput component We just added, we can import GoalInput from ./components/GoalInput. And we can use this component here in that place, where we had all the input related markup before. And set this onAddGoal prop, which we expect to get here in our GoalInput component. And now, since we set this prop's value as a value for the onPress prop, and that prop wants a function to be executed, we should pass a function to onAddGoal in the App component. And we still pass our addGoalHandler here, just like this. Now what does change though is how we handle the user input. How we fetch the user input? Because this GoalInputHandler and the state that manages the entered input is in the wrong place now. We don't do this in the App component anymore. Because the TextInput element is in the GoalInput component. What we should do therefore is grab that state, and cut it from the App component, and move it into the GoalInput component, like this. For this, of course, we must make sure that we import useState from react, in this GoalInput component. So that we can use this function here. Now we got this state. We also need this GoalInputHandler function, which updates the state though. So that in the App component, only the courseGoals state and the addGoalHandler function is left. We will treat this function as second as well though. In GoalInput.js, we can now paste in that GoalInputHandler function. And therefore this is now, again, connected to onChangeText, where we point at this function. So this enteredGoalText is still being handled here. Now, the only problem is that this enteredGoalText is eventually needed in the App component, when we add a new goal. and therefore we also need to make sure that this data arrives here in addGoalHandler. The easiest way of ensuring this would be to expect the enteredGoalText as a parameter. So that whenever addGoalHandler is called, we get this text and we can use it in here. Now, this function is fine. But right now this text wouldn't be provided. addGoalHandler is passed as a value to onAddGoal on the GoalInput, and onAddGoal is forwarded to onPress, and onPress which ultimately calls this function does not provide this enteredGoalText. To make sure that it does, we have to change something in our code here. For example, we can add another function here in our GoalInput component file and name this function addGoalHandler, again. So now we have this function or a function with this name in both GoalInput and App, but that's no problem because we're in different components here. Hence, we have no name clash. Now in this function, I actually want to execute props onAddGoal. So I want to call this onAddGoal function, which we receive here manually And then, onPress is connected to this addGoalHandler function which I just added. By calling this function manually, I can now make sure that I forward my enteredGoalText. So this state, I passed this as a value to the function I receive on this onAddGoal prop. And therefore, since function is the addGoalHandler in the App component. That addGoalHandler function will receive the enteredGoalText because I'm passing it manually here. And again, this is nothing react-native specific. This is standard react. Now as extra bonus, we could also set our enteredGoalText to an empty string to clear it, whenever we added a new goal. We didn't do that before but we can do it now. And I think it is a change that makes sense. But of course, it's up to you whether you want to do that or not. Here, I will do it by setting the state back to an empty string. With all of that, back in App component, this should all work. We can now get rid of some unused imports again, which we don't need anymore. And if we now save everything, and reload the app on both devices, if I now learn react-native, this goal still gets added. Now what's not happening is that the input would be reset though. Actually internally it is. If I click add goal, you see there was no text. But it's not reflected here in the input element. The reason for that is that I'm resetting the state here in GoalInput, but I'm not binding the state to TextInput. We don't have any proper two way binding here. We just have one way binding. In the past, this didn't matter, because as we never changed the text besides typing into the TextInput field. But now since we're also changing the state here, like this by resetting it, we should add a value prop to TextInput, and bind this to the enteredGoalText. So that whenever this goal text changes, because we for example, reset it, this is reflected in the TextInput. If we now save this, and reload everything, I can, again, learn, react-native. Now it's reset. And I can add my goals. So this is now working. And now, we split this into multiple components. And in the end, as you see, here we had absolutely nothing react-native specific. Splitting our app and passing data and functions around, that all works just as you know it from react. - [Maximilian] We're making good progress. We're now able to add items to our list here, and we're managing this list in an efficient way. Now, what we're not able to do yet though, is remove items, and it would be nice if you could simply tap those items and they would be deleted. Now to make them tappable, if this would be a web app, all you have to do would be that you add an "onClick" prop to the item. That's how you would do it in the web. But this is not how it works in React Native. Instead here, if you wanna make an item pressable, you have to let React Native know. And you let React Native know by wrapping the item that should be pressable into a specific component provided by React Native. And that would be the "Pressable" component. React native also knows a component named "Touchable" and various related components like "TouchableHighlight," and "TouchableNativeFeedback," and "TouchableOpacity," but those are components that are not deprecated, but that should be replaced by "Pressable" now. So these "Touchable" components are the old React Native way. "Pressable" is the way forward. So we use "Pressable" by simply wrapping the item that should be pressable with it. Like This. In my "GoalItem," I wrap my view with "Pressable," and with that, this item becomes pressable. And whenever we press any item inside of "Pressable," so in this case, this view with this text, this "onPress" prop will trigger the function that we provide to it. So we should provide a function to "onPress" and since I plan on deleting items in the future, I will define this function in App.js, because here, I'm managing my "courseGoals" state, and here, I will have to delete items in the future. So I will add a "deleteGoalHandler" function here in App.js. And for the moment, I'll just "console.log('DELETE')" here in this function. We will of course replace this with proper code later. Now, "deleteGoalHandler" should be provided to the goal item, In the infer, I'll add a prop here, and since it's my component, it's my choice how this prop should be named, and I'll name it "onDeleteItem" and pass my "deleteGoalHanlder" function to that. A pointer to this "deleteGoalHandler" function is passed as a value to "onDeleteItem" on my "GoalItem" component. And now this "onDeleteItem" prop can be used in that component. And here, I can for example, simply forward it. Like that. We might tweak it later but for the moment, we can just do it like this. Now, if I save this, If I tap on one of these items, I get no visual feedback, but if I go back, you see the that "DELETE" was locked to the terminal. So indeed, this already works. 'Course, some visual feedback would be nice and we will add it in a second, but for the moment, it's great that this works. - [Maximilian] As a next step, we can now make sure that an item actually does get deleted. And for this, in the app component, in the deleteGoalHandler, it would be convenient if in this handler function, we would receive the ID of the to be deleted item. Because that allows us to uniquely identify and remove an item. So here in this function, we could then set our course goals again, to update this course goals state. And now the new state should be based on the old state where we wanna take the old state, but remove a item, and therefore we pass a function to this state updating function. 'Cause that's how we should update state in React if it's based on the previous state. So here, I again, get my current course goals as I did here, when we added a goal and I return the updated state. And the updated state which I return is current course goals which is in Array, dot filter. Filter is a built-in method in JavaScript, just as map was built-in method, which we can call on in Array. And filter will return a new Array, which is the old Array minus all the items we filtered out. Now filter itself takes a function, which has to return true or false and if this inner function returns true, an item is kept, if it returns false, our item is dropped. Now this inner function is executed by JavaScript for every item in this array and therefore, it receives these items as inputs, as parameters. In my case, these individual goals. And I wanna return false, if my goal has this ID here. So I will check if the goal ID, so this ID property on my goal object is not equal to the ID I'm receiving here. This will return true if there is no match, which is good because I want to keep items where there is no match, but if there is a match, if a item has the idea I'm looking to remove, this will return false because then the IDs are equal and then this item will be dropped and the new array will no longer contain it. That's how we can delete a course goal. Of course, we have one problem though, the ID which we expect to get here is currently not provided. In goal item, where I'm binding on the lead item to onpress, onpress won't give me that ID. Now to make sure that idea is provided, we could, again, define a little helper function here as we did it in goal input, where we added addGoalHandler, where we then manually called the function and passed our own parameter and that would be absolutely fine. But alternatively, we can also call the built in bind method on the function which we get through that onDeleteItem prop. Bind is a standard JavaScript function which basically allows you pre-configure a function for future execution. Now, the first value you pass to bind sets the this keyword in the to be executed function and we don't care about that here, so I'll just set it to this, but it doesn't matter. The second value, the second argument you pass to bind will be the first parameter received by the to be called function. And in my case, that should be the ID of the goal item that should be removed. So here I'll set this to props.id, so that the ID which I get through props on this goal item component is sent as a parameter value, queue the function that we receive on this onDeleteItem prop which is this delete goal handler function. Of course, for this to work, we must make sure that we do get an ID prop on the goal item component though. And currently that's not the case but we can update our code here and make sure at an ID prop is set on goal item and that would be itemdata.item.id. Now there would be other ways of solving this as well, but this will work and if we save this now and we tap a item, it is removed. So now I can add items, multiple items and I can then tap them to remove them. By the way, you could also add validation to make sure that empty items can't be added but here I will not do that to keep this app a bit simpler. But with that, we can remove items. Now what's missing though, is some styling, some visual feedback. At the moment, when I tap this item I get no visual feedback other than its disappearance. So let's focus on the styling next. - So let's now work on the styling of this pressable component or of this component if the item is currently pressed because at the moment we got no visual feedback. Now, adding some nice styling here is fairly easy for Android because there is a dedicated android_ripple prop which you you can set to an object where you can set the color of the ripple effect. And for example here, I could set this color to some dark gray by adding six Ds here, this hex code. And if I do that, if I set this value for the android_ripple prop here on Android, if I add a goal and I press this, there is a slight ripple effect. Let me show this again. Here, if I then press this. You see? There is this ripple effect around this item. Now, if you wanna have the ripple effect inside of that item instead, what we have to do is move pressable into our view here like this so that it only surrounds the text instead of the view box as well. If we do that and we reload all apps to make sure these changes get applied. Now, if we do this again on Android here, you will see there is a slight ripple effect on the item. Now, that ripple effect is now only on the text. Not on the overall container. And to fix this, what we can do is move our padding from the goal item which is the view, which is the container to the text because then the padding is part of the text and the ripple effect will take this padding into account as well. So now with that, if we set this up we got this ripple effect here. And of course, you can play around with the ripple color to get the look you want. You could, for example, also take this purple color here. And maybe choose a very dark purple as a color, and now we have this, which maybe looks a bit nicer. So, this is pretty easy on Android. Now on iOS, this doesn't have any effect though. Here, if I press this and keep it pressed so that we could see a potential effect, we don't see any effect at all. Now for iOS to add some styling, we can add the style prop to pressable which generally works like all your style props. It takes such a styling object but it also takes a function as an alternative. And this function will be called automatically by pressable whenever the press state changes. You will get a argument here, a parameter, with information about the current press state and you can use object destructuring to get hold of the pressed property that's part of this object you get. You could also name the overall parameter pressData and access pressData.pressed in that function. It's up to you. Here, I will use object destructuring to directly get that pressed property. So, that's provided by pressable. And now we can return different style objects based on the pressed state. We can define them down here of course. We could have our pressed item here. And there, we could say that we wanna set the opacity to 0.5, for example, to make it slightly transparent. With that up here, we can check pressed and if it's true, we return styles.pressedItem. Otherwise, we return no special styling. If we save this and I now do learn react native again, you'll notice that if I press this we also get some feedback here on iOS. Now of course, you could go for all kinds of feedback. You could also bring this view back into the pressable component here and add another surrounding view so that you can influence the style in greater detail, and you can, for example, also change the background color. Whatever you want. Here, I'll keep this simple feedback but now we also do have some feedback with help of this function form of this style property here. - [Maximilian Schwarzmüller] So again. We made good progress here. To conclude this section. I wanna improve the overall look and feel of this application a little bit though. And I wanna start by actually outsourcing this input part into a modal, modals are these overlays. That typically slide up or pop up, on mobile apps that overlay the main screen. And allow you to take some action, after which they disappear. Adding such a modal, and adding the input logic here into such a model, is thankfully pretty easy in React Native. Because it comes with a built in modal component. So, all you have to do in the goal input component, where I want to create that modal. Is, you import modal from React Native. And then you wrap that, around the content that should go into the modal. In my case here, that's the view with the text input and the button. If you do that, we have this look here. So our list of goals seems to be gone and the styling is a bit off. And as I add goals, I don't see them. The reason for that is, that we actually see the modal here. The overlay, which we have on the entire screen. Now, of course the modal shouldn't always be there though. Instead it would be nice to have a button on the start screen, that allows us to open the modal when we want to add a new goal. And then to have a button that allows us to close this modal here on this modal screen. Now let's start with that button that opens the modal. For this, I'll go back to App.js, and I want to add that button there. We still have the goal input component. But above that component, I wanna add a button. And for this I'll use the good old built in button. Though, of course we could also import "pressable". And build our own button, as you learned it a couple of minutes ago. Because the button here in the end, all it just uses is the "pressable" component or those old "touchable" components internally. But here, to save some time, I'll use the prebuilt button instead of building my own one. And I'll give this button a title off, "add new goal". I'll also give the button a color, through the color prop. Because "button" doesn't take a style prop. It doesn't support it. Because it is already pre-styled. That's why you can't influence it too much. If you do want to style your own button, you have to build your own button with the "pressable" component. And then some text and views inside of it. Here, with the pre-built button, we can change the color through the color prop though. And I will set color here to, actually to a string. And I will use the same purple, as I used here in goal item. For the background of my goals. I'll use this purple color here. And set this as a color of this button here. Like this. So now we have the button. But of course, we don't see the button if we save this. Because we still have the modal everywhere. Now this button should control the modal visibility. And for this we need "state", because the modal should either be visible or not. And that's a typical case for using "state". So, here in the app component, we can add a new piece of "state". And use, "use state" to initialize it and set it to false initially, because that will be my "modal is visible" state And the "set modal is visible" updating function, will allow me to change it. And initially the modal should not be visible. Now we wanna change this whenever the button is clicked. - So for this, I'll add a "function" here, maybe here, the exact position doesn't matter. Which I will name "start at goal handler". And in this function I want to set, "set modal is visible" to true. Because I wanna show the modal. Now, this "start at goal handler" function, should now be connected to this button. And this button, being a built in component has this on press prop - Which we now use to connect it to "start at goal handler". Now to show the modal only when this state is true. We could now render goal input conditionally, as we would do a it in most React Web Apps. We can add curly braces around that. And then check our "modal is visible" state. And if it's true, then we render goal input. Which internally contains this modal. If we do It like this and we save everything. Indeed we see the button here. And if I press the button, the modal appears But the model then is just there. There is no animation and nothing. And therefore that's typically not, how you would do that. Instead of just showing or hiding this component like this. A better approach is to embrace some of the props, "modal". This built-in modal component, offers to you. To be precise, this "modal" component has a "visible" prop. And if set to "true", the model is visible, If set to "false", it's not. Now, this is useful. Because in addition, modal also has a animation type prop. Where you can set how it will be animated. That there maybe is no animation at all. That it should fade. Or that it should slide in. And I will go for sliding. And now I just expect to get the, "should it be displayed or not" information, via props. So here I'll access "props.visible", though this prop name here is up to you. It could also be "show modal". But I'll choose "visible". And now we have to set this prop on goal input, in the app component. So here, I'll now add this "visible" prop. And set this equal to "modal is visible", which is true or false. And with that, if we now saved this. And we force a reload, by pressing R here in the terminal. Now the modal slides up. Of course we can't dismiss it at the moment. And the styling in there also is a bit off. So, therefore let's next focus on that styling. And let's then make sure that, we can also close this modal. - [Maximilian] So to work on the styling here. In the end we need to go into the GoalInput component. There, we have this model and in the model we have this View. Which in the end is responsible for controlling how the textInput and button are displayed. Now I wanna change the overall look. I now wanna have the button beneath the textInput and I wanna have another button in addition to add goal. Because that other button should allow us to close that model. Now to achieve this I will restructure this a bit. And I will actually add another View in here, below the textInput, and move my button into this View. And add another button here with a title of Cancel. So that I can add the goal or cancel adding. And this should in the future close my model. at the moment it won't do anything though. Now with that, we got that View in a View. But now I wanna change the styles of that outer View, which is the main View inside the model. Because it's the first element in the model. The top most element in the model. And on this input container, I wanna use flex 1. So that it takes all the available space in the model. But I wanna change the flexDirection back to column. And therefore we can also remove it because that is the default anyways. With this, if I save this, the buttons are now below the textInput. But they are totally stretched out, because we have space between for justifyContent. This should instead be center to make sure all the content is centered. This now looks way better. Now in addition these two buttons should be next to each other and therefore I added this View around the buttons. and I will give this View some styling. So here, maybe at the bottom, I'll add my buttonContainer object. And actually give this a flexDirection of row. So that the two buttons are next to each other. And then add this buttonContainer on this View. So here I'll add a style which is styles.buttonContainer. And with that, the buttons do sit next to each other. Now it would be nice if the buttons had maybe a fixed width and some spacing between them. And to achieve this, since I can't style these buttons, since they're built in and since I don't wanna build my own button which we could do but which is some extra work. I'll actually wrap each button into a View as well. Because then I can style that View instead of the button. And therefore still influence the look of the button a bit. So here I'll assign a style property to those Views here. And setup a dedicated styling object for those buttons. I'll name style object button. And for every button here I'll just make sure that it takes, lets say, 40% of the available width. And then we might want to add a marginHorizontal, So margin left and right, of eight pixels. So that we have some spacing between the buttons. And it's now this button style here which I wanna add to the Views that hold the buttons. And that's a quick and easy way of setting my own styles to the buttons even though I can't change the button style itself. But you can change the width or height with that, you can add margins between them. You wouldn't be able to change the color or text color though, if that was your plan you would have to build your own button. And in general, if you need more adjustments, you might wanna build your own button by using the pressable component. But this is good enough for now and it gives me these equal sized buttons below the textInput. I also wanna have some spacing between the textInputs and the buttons. And maybe we can shrink them a little bit. So to shrink them I'll change the width to 30% here or we set this to a fixed pixel width of 100 for example, like this. And for the spacing between the textInput and the buttons. On the buttonContainer I will add a marginTop of let's say, 8 or maybe 16. So now I save this there is some distance between the buttons and the textInput above the buttons. The textInput now also can become wider. So I will set the width of the textInput to 100%. And with that, I reloaded the app in between so I will reopen this, this is now wider. Now it would still be nice to have some area around that which is not occupied. And therefore on the overall container, Which is that root View in that model, I will add a little of padding in all directions and let's say add 16 pixels of padding. And now I'd say this doesn't look too bad. Last but not least we still have some extra spacing to the right of the textInput, because we had a margin to right and I wanna get rid of that as well. So now this does look quite good. And of course you can adjust this a bit further if you want to. Now I wanna make sure the model closes whenever we cancel or click add goal though. Because at the moment that's not happening. - [Maximilian] So to close the modal, whenever we click add goal or cancel, we have to react to taps on those buttons. And then in the end, we have to change the visibility state in the app component because modal is visible in the end controls whether the modal is shown or not. Now we already got a 'StartAddGoalHandler' which opens the modal. Now we can add a 'EndAddGoalHandler' which should set 'ModalIsVisible' to false. And now we just need to make sure this function gets called whenever a user taps on the 'Add Goal' or 'Cancel' buttons. Now, if a user taps on 'Add Goal', the 'AddGoalHandler' is triggered which triggers the function received on the 'onAddGoal' prop which turns out to be this function. So in order to close the modal if a goal was added, we just have to set 'ModalIsVisible' to false here as well or call the 'endAddGoalHandler' manually here. Both would work. Now to also close it, If we tap the cancel button, in goal input we have to add 'onPress' to this button as well, And then expect that we get a pointer to this 'endAddGoalHandler' passed into 'GoalInput' through props. So here we could expect that we get a function on a cancel prop. It's our component, so the prop name is up to you. Now we just have to make sure that this prop is provided in app component. Here we pass the 'onCancel' prop to the 'GoalInput' component and point at the end, 'addGoalHandler' function, so that this function is executed whenever the cancel button is clicked, or pressed. With that, if we save this. Indeed, if I click cancel the modal closes. And if I add a goal here, like this, and I click add goal, it also closes, but the goal is there. And of course it also works on Android. Both adding and removing, and opening and closing. - [Maximilian] Now to finally finish this app here. I wanna improve the overall look and feel, by changing some colors and by adding an image. Which is something we haven't done yet. But which is of course, something you will often do. And you should therefore know how to do. Now, adding an image, thankfully is easy. Because React Native has a component for it. There is an "image" component, which you can import from React Native. And just as you have, the "image" element for the web, in HTML. This is a component that helps with displaying an image. This "image" component is used in your JSX Code. And here I wanna display an image, right above the text input. So, I will add my image here. On this image, you can then add some style. Which we'll do in a second. But most importantly, you can also add a "source" prop. And this should point at the image you want to add. Now, when it comes to that image, you do find an example image attached. And you should download that image and move it into your "assets" folder. Or to be precise create an "images" folder in that "assets" folder. Because that "assets" folder is generally, the folder where static assets like images should be stored. And then move that attached image, into that "images" folder in the "assets" folder. And it's this "goal image", which you got attached. And now when it comes to linking to that image. It works differently than what you're used to from the web. We won't create some link here, which points to "assets/images/goal.png" at least not quite. It's not too wrong, but it wouldn't work like this. If I save this, you see, I get a warning. I get an error, this doesn't work. Instead, you have to import the image here with a special import syntax. You should use a "require" function. Which you might know from Node.js, if you worked with that. And to that "require" function, you pass the path to the image. However, the path is a relative path from the file in which you're using this "require" function. So, seen relatively from that goal input file, which is that file, where this "required" function gets used. We have to go up one level, to leave the "components" folder. And then dive into images and select the image. Now to go up one level we type ../, this means go to the parent folder. And then we dive into assets, images, goal.png. This is how we add an image. Now let's also add some styling to it. And for this, I'll add an "image styling" object in my style sheet here. And here we could set a width of let's say 100 pixels. And a height of 100 pixels. And give this a margin of 20 in all directions, to have some spacing around the image. As always, you can play around with the styling, to find your favorite styles. Now I wanna apply that style to my image. And thankfully the "image" element, the "image" Component, does support the style prop. And we can set "styles.image", as a value on that style prop. And with that, if we reload the app by pressing R here in the terminal. You will see nothing. As it seems. The reason for that is that the image is white. And we can't see that, because the background is also white. That's no problem because, I wanted to changed the background as well. And since we're in the modal here. This background can be changed. By setting a different background on this input container. Because that is our root element in the modal. And it defines the overall modal container look therefore. The modal itself does support the style prop. But for styling the overall modal background, you should use a nested view, as we are doing it here. And now here on this input container. We can add a background color. And I prepared a nice dark purple, which I'd like to use here. Which has to hex code 311b6b. And whilst we're here, I also wanna change some other styles. For example, we don't need the border at the bottom anymore. Because there is nothing below that. And that border here looks really strange. So I will remove that border. And I will also remove that margin to the bottom which I have here. So that these are the remaining styles that I have here. And with this, now we can see the image. Because now we got this nice purple background. Only in the modal though. We will work on the other background later. But here in the model, we got that. Of course, we now also might want to, tweak the text color here. When we enter something into this input field. And we might wanna tweak the buttons here as well. To make those look a bit prettier as well. Because currently they don't fit the background. But most importantly, we did now add the image. Which was the main task for this lecture. And as you saw, adding an image is super simple. With that "image" Component and this way of adding a source. So let's next improve the overall styling of those modal elements. The other elements, I mean. - [Tutor] So for improving the overall look and feel here, I wanna start by changing the button colors. For this, we can go to our JSX code because you learned that for these built in buttons, you change the colors with the color prop. And again, I prepared some hex codes, which I think look quite nice. And for adding an item here, I wanna use the code 5E0acc. And for canceling, I prepared another code, which is F31282. If we save this, this is how the buttons look like. And it looks good on Android, but on iOS, it's a bit hard to read I would say. This is a bit hard to read. So actually, we might wanna tweak this and pick a slightly lighter purple, like B180f0, which I think looks good on iOS as well. It doesn't look as good on Android, but for the moment I don't wanna dive into writing different code for different platforms. We will do that later in the course, but for now let's stick to this uniform solution here, where we have the same code for both platforms. Of course, feel free to optimize the app for one of the two platforms. For example, if you're on windows and you can't test this on iOS anyways, you can of course choose a prettier color for this button there. But we got these buttons now, let's now work on the text input styling. And for this, we got this text input styling object here. In there, I wanna to change the border color a little bit and choose E4d0ff. And also give this a background color which should be the same color. So I'll just copy that as a background for the text input. I will now also change the color of the text that's entered to 120438, which is another prepared hex code. Since I added a border, I also wanna change the border radius, so that I have some rounded corners with border radius and set this to six pixels. And with that, that is how this input looks like. And I think that doesn't look too bad. Last but not least, I will ramp up the padding a little bit though, and change it to 16, so that we got this padding here. So that's now how this model looks like. And I would say it doesn't look too bad. We can now learn React Native and this app looks quite nice. I just wanna switch to button order because I ended a bit more intuitive if the add button is on the right, but of course, this comes down to personal preference and is totally up to you. But now, this works. Last but not least, I also wanna improve the styling of this main screen though. Because I think that white background color isn't too pretty. Here, I prepared a little color for us. And it has the hex code 1e085a. Now, if we set it like this, this works and we got this as a background color. And this works just fine here. But if we had multiple screens in this app, so not just the model, but also other screens, which we will have later once we add navigation, then manually setting the background color like this all the time, can become annoying. Therefore what you can do when using expo, is you can go to the app.json file. And in that file, you can actually also add a special background color configuration item and set this to a hex code. And this will then automatically be applied as a background color to all screens by expo. So if I now reload after adding this to app.json and saving that file, we also got this background color, but now it's applied by expo to all the main screens, not to the model, but to all the main screens that are not overlays. Here, we only have one screen, so it didn't matter. But this can be the more convenient approach if you do have multiple screens. Of course, like this, I'm not totally happy with the way this add new goal button looks. I think it's a bit hard to see on iOS. Therefore, what I will do is in App.js, I will change the color of this button. And we could go for a lighter purple like this. And I think that looks a bit nicer. So now with the styling changed, there's one thing that might become obvious. The status bar is really difficult to see on both these devices. The reason for that is that it's still black, that it doesn't know that we have a dark background. Now, thankfully, expo gives us a solution for that. We can import a special component from expo. And that component is the status bar. We can import it from expo-status-bar, which is a standalone package which is already part of this project. This package here. This is a component which we can use to fine tune the look of the status bar. We simply use this status bar as a component, here in our JSX code, in this root app component. So here we can add StatusBar. And since it's now next to another sibling component, right at the top of the return to JSX code, I will wrap it with such a fragment, since you're not allowed to have sibling elements at the root level of JSX code otherwise. So we add this wrapping fragment and add the StatusBar component next to our root view component. And on this StatusBar component, you can now set a style prop, which one's a string though? And you can now set the status bar to dark or light or let it infer it automatically. Now, auto doesn't work here. So I will set it to light. And if I do that, the status bar becomes white and is now way easier to see again. And that is definitely a tweak we also wanna apply so that we do have an app that looks good and that still allows the user to see crucial phone information like the battery or the time. - [Maximilian] So, that's it for this course section. We learned a lot about React Native. We built the first basic application here, where we can add our course goals, and whilst building this application, we learned a lot about building user interfaces with React Native, in general. You learned that you must use these built-in core components, for example. You are not allowed to use HTML elements like div's or anything like that. Instead, you build the entire user interface and all your custom components from those built-in components. But then you can combine them as you need to, to build your own elements and features. You also learned how styling works, that you create such style sheet objects which hold nested objects, which you can then assign to different elements in your JSX code. In those nested objects, we have CSS-like properties, which allow us to set margins, paddings, colors, and all these things. Now even though it looks a bit like CSS, or the names are similar, it isn't CSS. We have no inheritance and in general, it's just not CSS, it's JavaScript and under the hood, React Native translates our style settings to the Native style instructions for the different platforms. We, for example, saw that we had problems assigning rounded corners to these elements on iOS, whereas it worked without issues on Android and therefore, its really important to keep in mind that we have two different platforms and React Native just does its best to talk to both platforms and transform our instructions for them. Now, what we also of course learned, is that besides the components and the styling, we write regular React applications. We can still use state, we can react to events, those events are just not called onclick, but instead onpress. But then we can react to them, we can change state, we can output state and we can do all these things and this part, works exactly as you're used to. There's nothing special about this. React Native Plus React is exactly as React Web Plus React when it comes to managing state and so on. Now, we saw differences when it came to outputting lists though. We did this with a scroll view, but then we switched to flat list for better performance. Which is another built-in core component. And you will see cases like this from time-to-time throughout the course, where we have a special solution for the Native platforms for better performance or a Native look and feel. But that's it for the basics for now. In the end it's not too complex, it's a React app, just with a different target platform, but of course it is something you must get used to. Working with those built-in components, setting up styling like this. It takes practice to get used to that. And thankfully we'll have plenty of practice throughout this course, because this was just the first real section and just the first app. We're going to build way more and we're going to learn way more throughout the rest of this course. I hope you enjoyed this "Getting Started" guide which got you started with React Native, with the project setup, and with building your first app. If you liked this, and if you would like to learn more, for example, how to use native device features, how to send push notifications, how to add multiple page navigation to your app and much more - then my complete course on React Native might be interesting to you! And you'll find a link to the course, with a nice discount, directly below the video. And I'd of course love to welcome you on board of this course and continue this journey into React Native together with you.
Info
Channel: Academind
Views: 556,124
Rating: undefined out of 5
Keywords: react, react.js, reactjs, reactjs native, react.js native, react native, react native course, react native tutorial, react native app, maximilian schwarzmueller, maximilian schwarzmuller, maximilian schwarzmüller
Id: VozPNrt-LfE
Channel Id: undefined
Length: 204min 29sec (12269 seconds)
Published: Wed May 18 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.