Build Quotes App with React Native in 5 Minutes
Three days ago, I just give my first tech talk about “How to Get Started as a Mobile Developer” in Jakarta. I talk about what’s going on with React Native this year, the good and bad things about it, what will change in the future, and how to get started with it. It was a very great experience and pretty much successful.
In the live coding session, I decided to build a quotes app with React Native, so that you can be inspired everyday with popular quotes. It’s not a tutorial, but I just want to demonstrate people that they can build an app very fast (five minutes) with React Native.
The UI is very straight forward, it shows the quote and the author inside text component, and a button to show another quote randomly from a fake REST API with JSON Server.
So, in this tutorial, I’m going to show you step-by-step on how to build that quotes app from my tech talk live coding demo. Enjoy!
Quotes REST API
As I mentioned previously, I use JSON Server to store and serve all of the quotes data. If you don’t know what JSON Server is, basically it’s just a fake REST API generator, created by this awesome dude, which we can use to serve a json file in an Node.js HTTP server.
Before we get started with it, we need to installed globally first by running this command inside your command-line.
$ npm install -g json-server
Then, we need a file that holds our data that looks something like this.
{
"quotes": [
{
"text": "The Dream Is Free But the Hustle Is Sold Separately",
"author": "George Koufalis"
},
{
"text": "Mankind invented the atomic bomb, but no mouse would ever construct a mousetrap.",
"author": "Albert Einstein"
},
{
"text": "Talk is cheap. Show me the code.",
"author": "Linus Torvalds"
}
// ...
]
}
Here, we have an object that contains quotes
property that represents array popular quotes from successful people. To serve this data, we can run json-server
command inside our terminal.
$ json-server quotes.json
Initialize React Native Project
We have our server up and running, now it’s time to work on the client side or our app. Here, we will use Expo, which is the most convenient way to start a React Native project. We also get several built-in native features like Camera, Location, File System, even Social Authentication.
First, you need to install Expo by running this command.
$ npm install -g expo-cli
This command will install the Expo CLI from npm package registry.
Second, initialize a new Expo project by running expo init
command.
$ expo init <your-app-name>
Type your app name and your package name. Then, choose Blank template option.
Finally, open App.js
and the starter code will looks something like this.
import React from "react"
import { StyleSheet, Text, View } from "react-native"
export default function App() {
return (
<View style={styles.container}>
<Text>Open up App.js to start working on your app!</Text>
</View>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center",
},
})
Now you can execute expo start
in your terminal to run the app on a simulator/emulator, browser, or on a real device.
Fetch Random Quote
There are several approaches to fetch our quotes from the REST API. In this tutorial, we will going to use the new React feature called React Hooks. It’s a handy feature which you can use to literally do everything that class component could do inside a functional component. More on that in this post.
function useQuote() {
const [quote, setQuote] = React.useState(null)
return quote
}
Here we define a useQuote
function, which a React custom hook where we want to fetch random quote. The first thing we did here is to create a quote
state with useState
function from React.
Inside our App
component, we can display our quote from the useQuote
hook by calling it like a normal hook.
export default function App() {
const quote = useQuote()
return (
<View style={styles.container}>
{quote && (
<React.Fragment>
<Text>{quote.text}</Text>
<Text>{quote.author}</Text>
</React.Fragment>
)}
</View>
)
}
Because fetching data from server is asynchronous, we need to check wether our quote is fetched or not. In JavaScript, we can wrap our component with &&
expression. So that our component won’t be rendered whenever the expression returns false
.
Finally, we display our text
and author
object property with the Text
component provided by the react-native
.
To make our app look cleaner, we can define some styles to our quote text using React Native StyleSheet
.
export default function App() {
const quote = useQuote()
return (
<View style={styles.container}>
{quote && (
<React.Fragment>
<Text style={styles.quoteText}>{quote.text}</Text>
<Text style={styles.quoteAuthor}>{quote.author}</Text>
</React.Fragment>
)}
</View>
)
}
// New
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center",
},
quoteText: {
fontSize: 24,
textAlign: "center",
},
quoteAuthor: {
marginTop: 15,
fontSize: 18,
color: "#616161",
},
})
So far so good, now we need to fetch our quotes from our server inside useEffect
hook.
function useQuote() {
const [quote, setQuote] = React.useState(null)
React.useEffect(() => {
// Fetch data here
}, [])
return quote
}
Here, we use useEffect
hook to let us run a function when our component is loaded to the screen. In addition, we also can use this hook to do something when some state has changed.
If you wonder why the second parameter of the useEffect
hook is an empty array. That’s because we don’t want to listen to any state changes inside our custom hook. To find our more about useEffect
hook, checkout this post.
Inside this useEffect
, we can shoot a request to our server with fetch
method.
React.useEffect(() => {
fetch("http://localhost:3000/quotes")
.then((response) => response.json())
.then((quotes) => {
const randomIndex = Math.floor(Math.random() * (quotes.length - 1))
setQuote(quotes[randomIndex])
})
}, [])
The randomIndex
constant generates a random number from 0 to the maximum index of quotes array. We use this number to get a random quote and update our quote
state with setQuote
function.
Random Quote Button
Now, our app is almost complete. The last thing to do is to add a button that will generate a new random quotes from the server when it pressed. So, we need a function to generate random quote from the server outside the useEffect
hook. We can add this functionality by refactoring our custom hook a little bit.
function useQuote() {
const [quote, setQuote] = React.useState(null)
React.useEffect(() => {
updateQuote() // New
}, [])
// New
function updateQuote() {
fetch("http://localhost:3000/quotes")
.then((response) => response.json())
.then((quotes) => {
const randomIndex = Math.floor(Math.random() * quotes.length)
setQuote(quotes[randomIndex])
})
}
return { quote, updateQuote }
}
Here, we move the useEffect
hook callback content to a new function called updateQuote
, which used to fetch a random quote from our server. So that, we can return our quote
state and the updateQuote
function to our component.
With this changes, we need to adapt our App
component. We can define a Button
component, provided by the react-native
package, to generate new random quote.
export default function App() {
const { quote, updateQuote } = useQuote() // Update
return (
<View style={styles.container}>
{quote && (
<React.Fragment>
<Text style={styles.quoteText}>{quote.text}</Text>
<Text style={styles.quoteAuthor}>{quote.author}</Text>
<Button onPress={updateQuote} title="Show Me Another Quote!" /> // New
</React.Fragment>
)}
</View>
)
}
Wrap Up
Our app is now completed!
To summarize this, here is the full code of our React Native quotes app in just 55 lines of JavaScript code!
import React, { useState, useEffect, Fragment } from "react"
import { StyleSheet, View, Text, Button } from "react-native"
function useQuote() {
const [quote, setQuote] = useState(null)
useEffect(() => {
updateQuote()
}, [])
function updateQuote() {
fetch("http://localhost:3000/quotes")
.then((response) => response.json())
.then((quotes) => {
const randomIndex = Math.floor(Math.random() * quotes.length)
setQuote(quotes[randomIndex])
})
}
return { quote, updateQuote }
}
export default function App() {
const { quote, updateQuote } = useQuote()
return (
<View style={styles.container}>
{quote && (
<Fragment>
<Text style={styles.quoteText}>{quote.text}</Text>
<Text style={styles.quoteAuthor}>{quote.author}</Text>
<Button onPress={updateQuote} title="Show Me Another Quote!" />
</Fragment>
)}
</View>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center",
padding: 25,
},
quoteText: {
textAlign: "center",
fontSize: 28,
},
quoteAuthor: {
fontSize: 18,
marginTop: 25,
},
})
Tags: React-Native, React, Javascript