React Native vs. React: Basic Syntax
Tags: reactnative, react, javascript
Published: 2020-08-10 14:45:09

I've just started taking [Stephen Grider's React Native course](https://www.udemy.com/course/the-complete-react-native-and-redux-course/), and he explains a lot of React and JSX concepts to people who might not be familiar with them. If you're like me and already know React, read on for just the info specific to React Native.

# React Native Elements - The First Three
Let's have a look at this React Native Component:
```jsx
import React from 'react';
import { Text, StyleSheet, View } from 'react-native';

const ComponentsScreen = () => {
  const name = 'Daniel';
  return (
    <View>
      <Text style={styles.headingStyle}>Getting started with React Native</Text>
      <Text style={styles.greetingStyle}>My name is {name}</Text>
    </View>
  );
};

const styles = StyleSheet.create({
  headingStyle: {
    fontSize: 45
  },
  greetingStyle: {
    fontSize: 20
  }
});

export default ComponentsScreen;
```
A few new things here! Let's break down that React Native import statement. 

###Text
Any time we want to show some text to the user, we have to wrap in in a `Text` component. Any text we try to display outside of this component will result in an error.

### StyleSheet
To give our elements CSS styling, we create style objects (just like we would in React), put them all into a bigger object, and then pass that object into `StyleSheet.create()`. You might be thinking, "Why can't we just define styles inline?" The good news is, we can! However, if we define a non-React-friendly property (like `fontsize`), `StyleSheet.create()` will catch it and throw an error for us. We miss out on this check if we define styles inline.

### View
If we want to render multiple JSX elements, we have to wrap them in a `View` component. In React we could have just used `div` tags, but those would result in an error in React Native.

# FlatLists
When we want to render a list of JSX elements from an array in React, we're used to using a `map` method. In React Native, we have to switch gears and make use of an element called `FlatList`.
```jsx
import React from 'react';
import { View, Text, StyleSheet, FlatList } from 'react-native';

const ListScreen = () => {
  const friends = [
    { name: "Friend A" },
    { name: "Friend B "},
    { name: "Friend 4" },
  ]
  return <FlatList data={friends} renderItem={element => {
    //some code here
  }}/>;
};

const styles = StyleSheet.create({});

export default ListScreen;
```
Looking at this element, the `data` attribute is easy enough to grok, but what about the `renderItem` attribute? Is that the same as a `map` function? Unfortunately, no. In the first iteration of `renderItem`, `element` would look like this:
```javascript
{
   item: { name: "Friend A" },
   index: 0
}
```
If we're only interested in the `item` value, we can use a bit of ES6 destructuring:
```jsx
const ListScreen = () => {
  const friends = [
    { name: 'Friend A' },
    { name: 'Friend B ' },
    { name: 'Friend 4' }
  ];
  return (
    <FlatList
      data={friends}
      renderItem={({ item }) => {
        return <Text>{item.name}</Text>;
      }}
    />
  );
};
```
Of course, just like in React, we have to define a `key` attribute every time we render a list. If we don't feel like declaring a `key` property for every item in our `friends` array, we can take advantage of React Native's `keyExtractor` method:
```jsx
return (
    <FlatList
      keyExtractor={friend => friend.name}
      data={friends}
      renderItem={({ item }) => {
        return <Text style={styles.textStyle}>{item.name}</Text>;
      }}
    />
  );
```
I know: "Ughhh, why can't we just use the map method?" Well, the upshot of `FlatList` is that we can add a couple of attributes to easily turn the list horizontal (think Netflix tiles!). Check it out:
```jsx
return (
    <FlatList
      horizontal
      showsHorizontalScrollIndicator={false}
      keyExtractor={friend => friend.name}
      data={friends}
      renderItem={({ item }) => {
        return <Text style={styles.textStyle}>{item.name}</Text>;
      }}
    />
  );
```
#Buttons
In the beginning of React Native, a component called `TouchableOpacity` was the sole equivalent of a button. It's powerful and allows for a lot of customization. However, it's not super intuitive, and a lot of developers starting out with React Native got hung up looking for a `Button` component, so the React Native team added one. It's essentially a simpler version of `TouchableOpacity`.
###Button components
A React Native `Button` component, unlike an HTML button, is a self-closing element. To render text inside it, we pass in a string as a `title` attribute.
```jsx
import React from 'react';
import { Text, StyleSheet, View, Button } from 'react-native';

const HomeScreen = () => {
  return (
    <View>
      <Text style={styles.text}>Hi there!</Text>
      <Button title='Go to Components Demo' />
    </View>
  );
};
```
A nice benefit of `Button` components is that they render with some styling right out of the box: blue text on iOS or white text on a blue background on Android.
###TouchableOpacity
A `TouchableOpacity`, on the other hand, comes with no styling out of the box, save for a momentary fade-out effect when it is pressed. To make things confusing, `TouchableOpacity` is NOT a self closing component, and we have to render some other element or elements between the tags.
```jsx
import React from "react";
import { View, Text, Button, TouchableOpacity } from "react-native";

const HomeScreen = () => {
  return (
    <View>
      <Text style={styles.text}>Hi there!</Text>
      <Button title='Go to Components Demo' />
      
      <TouchableOpacity>
        <Text>Go to List Demo</Text>
      </TouchableOpacity>
    </View>
  );
};
```
###Adding functionality
In React, we're used to giving buttons an `onClick` attribute with a callback function. We don't have a mouse to click with when we're using our phones, so the React Native equivalent is called `onPress`. Here's what that might look like using the `navigation` method from react-navigation-stack (specifics later in the article!):
```jsx
import React from "react";
import { View, Text, StyleSheet, TextInput } from "react-native";

const HomeScreen = ({ navigation }) => {
  return (
    <View>
      <Text style={styles.text}>Hi there!</Text>
      <Button
        onPress={() => navigation.navigate('Components')}
        title='Go to Components Demo'
      />
      <TouchableOpacity onPress={() => navigation.navigate('List')}>
        <Text>Go to List Demo</Text>
      </TouchableOpacity>
    </View>
  );
};
```

#Images
React Native also has a primitive element for images called `Image`. To render a local image, we pass the relative path into a `require()` function and assign it to the `source` attribute. Be careful: this is the full word `source`, not `src`!
```jsx
import React from "react";
import { View, Text, Image } from "react-native";

const ImageDetail = props => {
  return (
    <View>
      <Image source={require('../../assets/beach.jpg')} />
      <Text>{props.title}</Text>
    </View>
  );
};
```
One catch is that source has to be a static value. That means can’t write `<Image source={require(props.img)} />` — instead, we’d have to pass down the entire `require('../../assets.beach.jpg')` function call as a prop.

#Inputs
Adding a text input element seems pretty easy at first glance:
```jsx
import React from "react";
import { View, TextInput } from "react-native";

const TextScreen = () => {
  return (
    <View>
      <TextInput />
    </View>
  );
};
```
However, if we run this file as is, it’ll look like a blank screen. The `TextInput` is actually there and we can interact with it, but it has zero default styling: no borders, no background, nothing. Let’s take care of that now:

```jsx
const TextScreen = () => {
  return (
    <View>
      <TextInput style={styles.input} />
    </View>
  );
};

const styles = StyleSheet.create({
  input: {
    margin: 15,
    borderColor: "black",
    borderWidth: 1
  }
});
```
In addition, phones have auto-capitalize and autocorrect features we might not want to apply to our input. They’re both easy enough to disable:
```jsx
const TextScreen = () => {
  return (
    <View>
      <TextInput
        style={styles.input}
        autoCapitalize='none'
        autoCorrect={false}
      />
    </View>
  );
};
```
You might’ve expected `autoCapitalize` to be a boolean, but it’s not because we actually have a few capitalization schemes to choose from ( `sentences`, `characters`, `words`).
Next, we’re going to want to make this input a controlled input. In other words, we want to connect the input’s value and the component’s state, just like in React. In React, we have an event listener attribute called `onChange` and we set the state equal to `event.target.value`. In React Native, that listener is called `onChangeText` and simply receives a `newValue` as a parameter instead of an entire event object.
```jsx
const TextScreen = () => {
  const [name, setName] = useState("");

  return (
    <View>
      <Text>Enter name:</Text>
      <TextInput
        style={styles.input}
        autoCapitalize='none'
        autoCorrect={false}
        value={name}
        onChangeText={newValue => setName(newValue)}
      />
      <Text>My name is: {name}</Text>
    </View>
  );
};
```
One last note: the React Native equivalent of `onSubmit` for text inputs is `onEndEditing`.

#Navigation with react-navigation
I originally wasn’t going to talk about specific libraries in this article, but I figured anyone reading this would probably be wondering about it.

The react-navigation library is now in v5 with breaking changes, but `yarn add react-navigation` installed v4 when I ran it. Apparently v5 has been released but is still in beta or something. The react-navigation has documentation for upgrading to v5 if you’d like. Anywho, assuming you’ve created a React Native app with the Expo CLI, you can run this command to get some helper libraries:
```
expo install react-native-gesture-handler react-native-reanimated react-native-screens react-native-safe-area-context @react-native-community/masked-view
```
Also, we’ll need to install these:
```
yarn add react-navigation-stack @react-native-community/masked-view
```
Now we can get coding! First, we write a couple of imports:
```javascript
import { createAppContainer } from "react-navigation";
import { createStackNavigator } from "react-navigation-stack";
```
Note that `createStackNavigator` used to be in react-navigation, but now we have to import it from react-navigation-stack.

To get started, we declare a constant called `navigator` (by convention) and assign it a `createStackNavigator` call. This function takes two arguments, both objects: the first lists all our route names with their respective components, and the second defines other options.

Let’s tackle that first object argument. Assume we create a component called `SearchScreen`. To make our app open to the search screen, we import it into App.js and assign it to some (relevant) key in our object:
```javascript
{
   Search: SearchScreen
}
```
Then, to make our app open up to `SearchScreen` when it launches, we specify so in the second object. We can define other things as well, like the title we’d like in our header.
```javascript
{
   initialRouteName: "Search",
   defaultNavigationOptions: {
      title: "Business Search"
   }
}
```
Finally, we export our whole component by passing it in to `createAppContainer`. The whole App.js file would like this:
```jsx
import { createAppContainer } from "react-navigation";
import { createStackNavigator } from "react-navigation-stack";
import SearchScreen from "./src/screens/SearchScreen";

const navigator = createStackNavigator(
  {
    Search: SearchScreen
  },
  {
    initialRouteName: "Search",
    defaultNavigationOptions: {
      title: "Business Search"
    }
  }
);

export default createAppContainer(navigator);
```
So now how do we actually perform navigation? Easy enough: our child components are now going to receive `navigation` as a prop, and that prop contains a `navigate` method. If we wanted to navigate back to `SearchScreen`, we’d simply pass the string `'Search'` into `navigation.navigate()`. Hopefully this example from earlier makes more sense now:
```jsx
import React from "react";
import { View, Text, StyleSheet, TextInput } from "react-native";

const HomeScreen = ({ navigation }) => {
  return (
    <View>
      <Text style={styles.text}>Hi there!</Text>
      <Button
        onPress={() => navigation.navigate('Components')}
        title='Go to Components Demo'
      />
      <TouchableOpacity onPress={() => navigation.navigate('List')}>
        <Text>Go to List Demo</Text>
      </TouchableOpacity>
    </View>
  );
};
```

Hope this helps!

Follow me on [LinkedIn](https://www.linkedin.com/in/daniel-wagener-866868141/), [GitHub](https://github.com/DanielJWagener), and [Twitter](https://twitter.com/wagener_daniel)