Completing tasks
- React Native course
- Beginner
- Lesson 51/116
- 6 min
Add a completion toggle.
Completing tasks
Now we add the ability to complete tasks. When a task is tapped its done field becomes true and it gets struck through. The toggleTask function takes an id and flips the done field of the matching task in the tasks array. .map() rebuilds the array.
Example: const toggleTask = (id) => setTasks(tasks.map((t) => t.id === id ? { ...t, done: !t.done } : t)). The ternary flips done on the matching task and leaves the others as they are. Later inside renderItem a TouchableOpacity adds the tap and textDecorationLine: 'line-through' adds the strikethrough look.
Practice Add the toggle
Make two changes. (1) Below addTask add the toggleTask function: const toggleTask = (id) => setTasks(tasks.map((t) => t.id === id ? { ...t, done: !t.done } : t)). (2) Update renderItem to <TouchableOpacity onPress={() => toggleTask(item.id)}><Text style={{ textDecorationLine: item.done ? 'line-through' : 'none' }}>{item.text}</Text></TouchableOpacity>.
Starter code
import React from 'react';
import { SafeAreaView, View, Text, TextInput, Button, FlatList, TouchableOpacity, StyleSheet } from 'react-native';
export default function App() {
const [task, setTask] = React.useState('');
const [tasks, setTasks] = React.useState([]);
const addTask = () => {
setTasks([...tasks, { id: Date.now().toString(), text: task, done: false }]);
setTask('');
};
// Add the toggleTask function here
return (
<SafeAreaView style={styles.container}>
<Text>To-do</Text>
<TextInput placeholder="New task" value={task} onChangeText={setTask} />
<Button title="Add" onPress={addTask} />
<FlatList
data={tasks}
renderItem={({ item }) => <Text>{item.text}</Text>}
keyExtractor={(item) => item.id}
/>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: { flex: 1, padding: 16 }
});Sample solution
import React from 'react';
import { SafeAreaView, View, Text, TextInput, Button, FlatList, TouchableOpacity, StyleSheet } from 'react-native';
export default function App() {
const [task, setTask] = React.useState('');
const [tasks, setTasks] = React.useState([]);
const addTask = () => {
setTasks([...tasks, { id: Date.now().toString(), text: task, done: false }]);
setTask('');
};
const toggleTask = (id) => setTasks(tasks.map((t) => (t.id === id ? { ...t, done: !t.done } : t)));
return (
<SafeAreaView style={styles.container}>
<Text>To-do</Text>
<TextInput placeholder="New task" value={task} onChangeText={setTask} />
<Button title="Add" onPress={addTask} />
<FlatList
data={tasks}
renderItem={({ item }) => (
<TouchableOpacity onPress={() => toggleTask(item.id)}>
<Text style={{ textDecorationLine: item.done ? 'line-through' : 'none' }}>{item.text}</Text>
</TouchableOpacity>
)}
keyExtractor={(item) => item.id}
/>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: { flex: 1, padding: 16 }
});The strikethrough look
Completed tasks get a strikethrough; this visual cue tells the user the task is done. In React Native you use textDecorationLine: 'line-through' for this. When item.done is true the line appears, when false 'none' removes it.
Example: <Text style={{ textDecorationLine: item.done ? 'line-through' : 'none' }}>{item.text}</Text>. The ternary gives the text a dynamic style. This pattern fits React Native's declarative nature: styles depend on state, and the look updates automatically when state changes.
Questions and answers
Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.
1 Match each field to its meaning
| Term | Meaning |
|---|---|
id |
Unique key |
text |
Task text |
done |
Completion state |
toggleTask |
Flips done |
2 What does toggleTask do?
const toggleTask = (id) =>
setTasks(tasks.map((t) =>
t.id === id ? { ...t, done: !t.done } : t
));- Deletes the task from the array
- Flips the done field of the matching task Correct answer
- Adds a new task
- Marks all tasks done
Explanation: toggleTask flips the done field of the matching task.
3 Write the toggleTask body
const toggleTask = (id) => setTasks(tasks.map((t) => t.id === id ? { ...t,____: !t.done } : t));
const toggleTask = (id) => setTasks(tasks.map((t) => t.id === id ? { ...t,done: !t.done } : t));
Explanation: The done field is flipped; the task toggles completion.