React Native Reducer
Reducer
In a previous step I created an React Native application that used the React Context API using Context and Hooks to manage a To-Do List. We can now use reducers to centralise all methods to change the state of our application in a single function.
To-Do Context Provider
Without Reducer
import React, { createContext, useState } from 'react'
import {v4 as uuidv4} from 'uuid'
export const TodoItemContext = createContext()
const TodoItemContextProvider = ( {children} ) => {
const [items, setItems] = useState([
{ text: 'Have a great day!', id: `${uuidv4()}`}
])
const addItem = (item) => {
setItems([...items, {text: item, id: `${uuidv4()}`}])
}
const removeItem = (id) => {
setItems(items.filter((item) => {
return item.id !== id
}))
}
return (
<TodoItemContext.Provider value={{items, addItem, removeItem}}>
{children}
</TodoItemContext.Provider>
)
}
export default TodoItemContextProvider
With Reducer
import React, { createContext, useReducer } from 'react'
import {v4 as uuidv4} from 'uuid'
export const TodoItemContext = createContext()
const todosReducer = (state, action) => {
switch(action.type) {
case 'ADD_TODO':
return[...state, {text: action.text, id: `${uuidv4()}`}]
case 'REMOVE_TODO':
return state.filter((todo) => todo.id !== action.id)
default:
return state
}
}
const TodoItemContextProvider = ( {children} ) => {
const [todos, dispatch] = useReducer(todosReducer, [
{ text: 'Have a great day!', id: `${uuidv4()}`}
])
return (
<TodoItemContext.Provider value={{todos, dispatch}}>
{children}
</TodoItemContext.Provider>
)
}
export default TodoItemContextProvider
To-Do Component
Without Reducer
import React, { useContext, useState } from 'react'
import { Text, TouchableOpacity } from 'react-native'
import { TodoBackground, TodoList, TodoItem, LoginView, InputItem } from './_styles'
import { ThemeContext } from '../context/ThemeContext'
import { AuthContext } from '../context/AuthContext'
import { TodoItemContext } from '../context/TodoItemContext'
const ToDoList = () => {
const [todo, setTodo] = useState('')
const { isDarkTheme, darkTheme, lightTheme } = useContext(ThemeContext)
// if isDarkTheme is true return dark state / else light
const theme = isDarkTheme ? darkTheme : lightTheme
const { isLoggedIn, changeAuthStatus } = useContext(AuthContext)
const { items, addItem, removeItem } = useContext(TodoItemContext)
const handleChange = (text) => {
setTodo(text)
}
const handleAddItem = () => {
if(todo.length > 0)
addItem(todo)
setTodo('')
}
const handleRemoveItem = (id) => {
removeItem(id)
}
if (isLoggedIn) {
return (
<TodoBackground style={theme}>
{
items.length ? (
<TodoList
data={items}
keyExtractor={(item) => item.id}
showsVerticalScrollIndicator={false}
renderItem={({item}) => {
return <TouchableOpacity onPress={() => handleRemoveItem(item.id)}><TodoItem>{item.text}</TodoItem></TouchableOpacity>
}}
/>
) : (
<TodoItem>Nothing to do...</TodoItem>
)
}
<InputItem
value={todo}
onChangeText={(text) => handleChange(text)}
/>
<TodoItem onPress={handleAddItem}>
<Text>Add Item</Text>
</TodoItem>
<TodoItem onPress={changeAuthStatus}>
<Text>Logout</Text>
</TodoItem>
</TodoBackground>
)}
return (
<LoginView>
<TodoItem onPress={changeAuthStatus}>
<Text>Login</Text>
</TodoItem>
</LoginView>
)
}
export default ToDoList
With Reducer
import React, { useContext, useState } from 'react'
import { Text, TouchableOpacity } from 'react-native'
import { TodoBackground, TodoList, TodoItem, LoginView, InputItem } from './_styles'
import { ThemeContext } from '../context/ThemeContext'
import { AuthContext } from '../context/AuthContext'
import { TodoItemContext } from '../context/TodoItemContext'
const ToDoList = () => {
const [todo, setTodo] = useState('')
const { isDarkTheme, darkTheme, lightTheme } = useContext(ThemeContext)
// if isDarkTheme is true return dark state / else light
const theme = isDarkTheme ? darkTheme : lightTheme
const { isLoggedIn, changeAuthStatus } = useContext(AuthContext)
const { todos, dispatch } = useContext(TodoItemContext)
const handleChange = (text) => {
setTodo(text)
}
const handleAddItem = () => {
if(todo.length > 0)
dispatch({type: 'ADD_TODO', text: todo})
setTodo('')
}
const handleRemoveItem = (id) => {
dispatch({type: 'REMOVE_TODO', id})
}
if (isLoggedIn) {
return (
<TodoBackground style={theme}>
{
todos.length ? (
<TodoList
data={todos}
keyExtractor={(todo) => todo.id}
showsVerticalScrollIndicator={false}
renderItem={({ item }) => {
return <TouchableOpacity onPress={() => handleRemoveItem(item.id)}><TodoItem>{item.text}</TodoItem></TouchableOpacity>
}}
/>
) : (
<TodoItem>Nothing to do...</TodoItem>
)
}
<InputItem
value={todo}
onChangeText={(text) => handleChange(text)}
/>
<TodoItem onPress={handleAddItem}>
<Text>Add Item</Text>
</TodoItem>
<TodoItem onPress={changeAuthStatus}>
<Text>Logout</Text>
</TodoItem>
</TodoBackground>
)}
return (
<LoginView>
<TodoItem onPress={changeAuthStatus}>
<Text>Login</Text>
</TodoItem>
</LoginView>
)
}
export default ToDoList