React Fundamentals
React Native runs on React, a popular open source library for building user interfaces with JavaScript. To make the most of React Native, it helps to understand React itself. This section can get you started or can serve as a refresher course.
We’re going to cover the core concepts behind React:
- components
- JSX
- props
- state
If you want to dig deeper, we encourage you to check out React’s official documentation.
Your first component
The rest of this introduction to React uses cats in its examples: friendly, approachable creatures that need names and a cafe to work in. Here is your very first Cat component:
- Function Component Example
- Class Component Example
Here is how you do it: To define your Cat
component, first use JavaScript’s import
to import React and React Native’s Text
Core Component:
import React from 'react';
import { Text } from 'react-native';
Your component starts as a function:
const Cat = () => {};
You can think of components as blueprints. Whatever a function component returns is rendered as a React element. React elements let you describe what you want to see on the screen.
Here the Cat
component will render a <Text>
element:
const Cat = () => {
return <Text>Hello, I am your cat!</Text>;
};
export default Cat;
You can export your function component with JavaScript’s export default
for use throughout your app like so:
const Cat = () => {
return <Text>Hello, I am your cat!</Text>;
};
export default Cat;
Class components tend to be a bit more verbose than function components.
You additionally import Component
from React:
import React, { Component } from 'react';
Your component starts as a class extending Component
instead of as a function:
class Cat extends Component {}
Class components have a render()
function. Whatever is returned inside it is rendered as a React element:
class Cat extends Component {
render() {
return <Text>Hello, I am your cat!</Text>;
}
}
And as with function components, you can export your class component:
class Cat extends Component {
render() {
return <Text>Hello, I am your cat!</Text>;
}
}
export default Cat;
This is one of many ways to export your component. This kind of export works well with the Snack Player. However, depending on your app’s file structure, you might need to use a different convention. This handy cheatsheet on JavaScript imports and exports can help.
Now take a closer look at that return
statement. <Text>Hello, I am your cat!</Text>
is using a kind of JavaScript syntax that makes writing elements convenient: JSX.
JSX
React and React Native use JSX, a syntax that lets you write elements inside JavaScript like so: <Text>Hello, I am your cat!</Text>
. The React docs have a comprehensive guide to JSX you can reference to learn even more. Because JSX is JavaScript, you can use variables inside it. Here you are declaring a name for the cat, name
, and embedding it with curly braces inside <Text>
.
Any JavaScript expression will work between curly braces, including function calls like {getFullName("Rum", "Tum", "Tugger")}
:
You can think of curly braces as creating a portal into JS functionality in your JSX!
Because JSX is included in the React library, it won’t work if you don’t have
import React from 'react'
at the top of your file!
Custom Components
You’ve already met React Native’s Core Components. React lets you nest these components inside each other to create new components. These nestable, reusable components are at the heart of the React paradigm.
For example, you can nest Text
and TextInput
inside a View
below, and React Native will render them together:
If you’re familiar with web development,
<View>
and<Text>
might remind you of HTML! You can think of them as the<div>
and<p>
tags of application development.
On Android, you usually put your views inside
LinearLayout
,FrameLayout
,RelativeLayout
, etc. to define how the view’s children will be arranged on the screen. In React Native,View
uses Flexbox for its children’s layout. You can learn more in our guide to layout with Flexbox.
You can render this component multiple times and multiple places without repeating your code by using <Cat>
:
Any component that renders other components is a parent component. Here, Cafe
is the parent component and each Cat
is a child component.
You can put as many cats in your cafe as you like. Each <Cat>
renders a unique element—which you can customize with props.
Props
Props is short for “properties.” Props let you customize React components. For example, here you pass each <Cat>
a different name
for Cat
to render:
Most of React Native’s Core Components can be customized with props, too. For example, when using Image
, you pass it a prop named source
to define what image it shows:
Image
has many different props, including style
, which accepts a JS object of design and layout related property-value pairs.
Notice the double curly braces
{{ }}
surroundingstyle
‘s width and height. In JSX, JavaScript values are referenced with{}
. This is handy if you are passing something other than a string as props, like an array or number:<Cat food={["fish", "kibble"]} age={2} />
. However, JS objects are also denoted with curly braces:{width: 200, height: 200}
. Therefore, to pass a JS object in JSX, you must wrap the object in another pair of curly braces:{{width: 200, height: 200}}
You can build many things with props and the Core Components Text
, Image
, and View
! But to build something interactive, you’ll need state.
State
While you can think of props as arguments you use to configure how components render, state is like a component’s personal data storage. State is useful for handling data that changes over time or that comes from user interaction. State gives your components memory!
As a general rule, use props to configure a component when it renders. Use state to keep track of any component data that you expect to change over time.
The following example takes place in a cat cafe where two hungry cats are waiting to be fed. Their hunger, which we expect to change over time (unlike their names), is stored as state. To feed the cats, press their buttons—which will update their state.
- State with Function Components
- State with Class Components
You can add state to a component by calling React’s useState
Hook. A Hook is a kind of function that lets you “hook into” React features. For example, useState
is a Hook that lets you add state to function components. You can learn more about other kinds of Hooks in the React documentation.
First, you will want to import useState
from React like so:
import React, { useState } from 'react';
Then you declare the component’s state by calling useState
inside its function. In this example, useState
creates an isHungry
state variable:
const Cat = (props) => {
const [isHungry, setIsHungry] = useState(true);
// ...
};
You can use
useState
to track any kind of data: strings, numbers, Booleans, arrays, objects. For example, you can track the number of times a cat has been petted withconst [timesPetted, setTimesPetted] = useState(0)
!
Calling useState
does two things:
- it creates a “state variable” with an initial value—in this case the state variable is
isHungry
and its initial value istrue
- it creates a function to set that state variable’s value—
setIsHungry
It doesn’t matter what names you use. But it can be handy to think of the pattern as [<getter>, <setter>] = useState(<initialValue>)
.
Next you add the Button
Core Component and give it an onPress
prop:
<Button
onPress={() => {
setIsHungry(false);
}}
//..
/>
Now, when someone presses the button, onPress
will fire, calling the setIsHungry(false)
. This sets the state variable isHungry
to false
. When isHungry
is false, the Button
’s disabled
prop is set to true
and its title
also changes:
<Button
//..
disabled={!isHungry}
title={isHungry ? 'Pour me some milk, please!' : 'Thank you!'}
/>
You might’ve noticed that although
isHungry
is a const, it is seemingly reassignable! What is happening is when a state-setting function likesetIsHungry
is called, its component will re-render. In this case theCat
function will run again—and this time,useState
will give us the next value ofisHungry
.
Finally, put your cats inside a Cafe
component:
const Cafe = () => {
return (
<>
<Cat name="Munkustrap" />
<Cat name="Spot" />
</>
);
};
The older class components approach is a little different when it comes to state.
As always with class components, you must import the Component
class from React:
import React, { Component } from 'react';
In class components, state is stored in a state object:
export class Cat extends Component {
state = { isHungry: true };
//..
}
As with accessing props with this.props
, you access this object inside your component with this.state
:
<Text>
I am {this.props.name}, and I am
{this.state.isHungry ? ' hungry' : ' full'}!
</Text>
And you set individual values inside the state object by passing an object with the key value pair for state and its new value to this.setState()
:
<Button
onPress={() => {
this.setState({ isHungry: false });
}}
// ..
</Button>
Do not change your component's state directly by assigning it a new value with
this.state.hunger = false
. Callingthis.setState()
allows React to track changes made to state that trigger rerendering. Setting state directly can break your app's reactivity!
When this.state.isHungry
is false, the Button
’s disabled
prop is set to false
and its title
also changes:
<Button
// ..
disabled={!this.state.isHungry}
title={
this.state.isHungry
? 'Pour me some milk, please!'
: 'Thank you!'
}
/>
Finally, put your cats inside a Cafe
component:
class Cafe extends Component {
render() {
return (
<>
<Cat name="Munkustrap" />
<Cat name="Spot" />
</>
);
}
}
export default Cafe;
See the
<>
and</>
above? These bits of JSX are fragments. Adjacent JSX elements must be wrapped in an enclosing tag. Fragments let you do that without nesting an extra, unnecessary wrapping element likeView
.
Now that you’ve covered both React and React Native’s Core Components, let’s dive deeper on some of these core components by looking at handling <TextInput>
.