Skip to main content

React Native Reducer

Victoria Harbour, Hongkong

Github Repository

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