June 05, 2024
Building a Goals App with React Native: Core Concepts and Styling
Building a Goals App with React Native: Core Concepts and Styling
Introduction
In this post, we are going to dive into React Native core concepts, explore its components, build user interfaces, and learn how to style these components. We will also add interactivity to our project by implementing state management with React. Our project will be a simple goals application.
To get started, please follow up on my previous post .
Introducing the App.tsx File
In the App.tsx
file, we have a functional component similar to a web React component, but instead of HTML elements like <div>
and <p>
, we use React Native components. React Native does not use CSS; instead, it uses a class object called StyleSheet
from the React Native package. This object has a create
method that accepts key-value pairs, similar to CSS inline styling, and returns an object with these styles. It is good practice to define component styling within the component itself, as shown below:
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
In our functional component App
, we can use the style as follows:
import { StatusBar } from 'expo-status-bar';
import { StyleSheet, Text, View } from 'react-native';
export default function App() {
return (
<View style={styles.container}>
<Text>Hello world</Text>
<StatusBar style="auto" />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
```
Text
and View
are two of the most important built-in components in React Native for building user interfaces. You can think of them as the <p>
and <div>
tags in web development, respectively. They are both imported from the react-native
package.
Find the list of React Native components in the docs: React Native Components.
Styling in React Native
Styling can be done in two ways: inline styling by using props on the core components or using the StyleSheet
objects. Styles are written in JavaScript, with many properties inspired by CSS, though not all property names are the same.
Example using inline styling:
import { StyleSheet, Text, View, Button } from 'react-native';
export default function App() {
return (
<View style={styles.container}>
<View>
<Text>Another Text</Text>
</View>
<Text style={{ margin: 16, borderWidth: 2, borderColor: 'red', padding: 16 }}>
This is how Texts are rendered
</Text>
<Button title="button" />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
Example using StyleSheet
objects:
import { StyleSheet, Text, View, Button } from 'react-native';
export default function App() {
return (
<View style={styles.container}>
<View>
<Text style={styles.textContainer}>Another Text</Text>
</View>
<Text style={styles.inlineText}>
This is how Texts are rendered
</Text>
<Button title="button" />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
textContainer: {
margin: 16,
padding: 2,
borderWidth: 2,
borderColor: 'blue',
},
inlineText: {
margin: 16,
borderWidth: 2,
borderColor: 'red',
padding: 16,
},
});
```
Working with Layouts
In React Native, layouts are created using Flexbox. Unlike in web development, Flexbox is added to the View
component by default, and the default direction is column.
import { StyleSheet, Text, View, Button, TextInput } from 'react-native';
export default function App() {
return (
<View style={styles.appContainer}>
<View style={styles.inputContainer}>
<TextInput style={styles.textInput} placeholder="Your course goal!" />
<Button title="Add Goal" />
</View>
<View style={styles.goalsContainer}>
<Text>List of goals...</Text>
</View>
</View>
);
}
const styles = StyleSheet.create({
appContainer: {
paddingTop: 50,
paddingHorizontal: 16,
flex: 1,
},
inputContainer: {
flex: 1,
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 24,
borderBottomWidth: 1,
borderBottomColor: '#cccccc',
},
textInput: {
borderWidth: 1,
borderColor: '#cccccc',
width: '70%',
marginRight: 8,
padding: 8,
},
goalsContainer: {
flex: 5,
},
});
Handling Events
Interactivity is crucial in most apps. We handle events using event listeners, similar to web React apps. We will handle two events: a click on the "Add Goal" button and keystrokes on the text input element to capture user input.
import { useState } from 'react';
import { StyleSheet, Text, View, Button, TextInput } from 'react-native';
export default function App() {
const [goalText, setGoalText] = useState('');
function goalInputHandler(text: string) {
console.log(text);
setGoalText(text);
}
function addGoalHandler() {
console.log('Button clicked:', goalText);
}
return (
<View style={styles.appContainer}>
<View style={styles.inputContainer}>
<TextInput
style={styles.textInput}
placeholder="Your course goal!"
onChangeText={goalInputHandler}
/>
<Button title="Add Goal" onPress={addGoalHandler} />
</View>
<View style={styles.goalsContainer}>
<Text>List of goals...</Text>
</View>
</View>
);
}
const styles = StyleSheet.create({
appContainer: {
paddingTop: 50,
paddingHorizontal: 16,
flex: 1,
},
inputContainer: {
flex: 1,
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 24,
borderBottomWidth: 1,
borderBottomColor: '#cccccc',
},
textInput: {
borderWidth: 1,
borderColor: '#cccccc',
width: '70%',
marginRight: 8,
padding: 8,
},
goalsContainer: {
flex: 5,
},
});
Managing the Goals List
We will use state to manage our goals list, as it needs to be updated frequently on the UI.
import { useState } from 'react';
import { StyleSheet, Text, View, Button, TextInput } from 'react-native';
export default function App() {
const [goalText, setGoalText] = useState('');
const [goals, setGoals] = useState<string[]>([]);
function goalInputHandler(text: string) {
setGoalText(text);
}
function addGoalHandler() {
setGoals((prevGoals) => [...prevGoals, goalText]);
}
return (
<View style={styles.appContainer}>
<View style={styles.inputContainer}>
<TextInput
style={styles.textInput}
placeholder="Your course goal!"
onChangeText={goalInputHandler}
/>
<Button title="Add Goal" onPress={addGoalHandler} />
</View>
<View style={styles.goalsContainer}>
{goals.map((goal, index) => (
<View key={index} style={styles.goalItem}>
<Text style={styles.goalText}>{goal}</Text>
</View>
))}
</View>
</View>
);
}
const styles = StyleSheet.create({
appContainer: {
paddingTop: 50,
paddingHorizontal: 16,
flex: 1,
},
inputContainer: {
flex: 1,
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 24,
borderBottomWidth: 1,
borderBottomColor: '#cccccc',
},
textInput: {
borderWidth: 1,
borderColor: '#cccccc',
width: '70%',
marginRight: 8,
padding: 8,
},
goalsContainer: {
flex: 5,
},
goalItem: {
margin: 8,
padding: 8,
borderRadius: 6,
backgroundColor: '#5e0acc',
},
goalText: {
color: 'white',
},
});
Here, we keep our goals in an array called goals
, and when we add a goal, we append it to this array. For each goal in the list, we render a Text
component wrapped inside a View
to style it. React Native requires a key prop for each element in a list to efficiently manage re-renders.
Conclusion
We have successfully built a simple goals application using React Native. We covered core concepts like components, state management, styling, and handling events. This is just the beginning; you can further enhance this application by adding more features, such as editing or deleting goals, persisting data, and more.
Stay tuned for more advanced topics in React Native in upcoming posts!
Github Repo: https://github.com/Intuneteq/react-native-tutorials/tree/tutorial-two
React Native Doc: https://docs.expo.dev/
876 views