From Novice to Pro: Master React Navigation and Context API - Level 2
Learn how to use react navigation and context api in react native with typescript

Turjoy • February 16, 2024
We are gonna explore two things in this article.
Navigation between app screens and global state management.
For global state management, we will be using Context API.
Context API comes with the React library.
Global state management is basically keeping a central data store.
It also manages functions that work on the data to change its state.
This data and functions are then available from any screens.
Note that we are still not persisting data.
That is, when app restarts you won't get past data.
Goals
The goals are:
-
How react native apps navigate from one screen to another (React Navigation)
-
How data is accessed in different screens from a central store (Context API)
Design Plan
You should be creating wireframes first (hand-drawn or digital).
Refer to the wire framing section of past blog.
Here lets start with the high fidelity designs built with figma.
We will be needing three screens:
- Todo List Screen
- Add Todo Screen
- Todo Details Screen
Below they are shown.



Starting Code and Final Code
We have learned how to make a basic todo app with local state management.
We had used react hooks to manage state locally.
MUI in react native paper was used to skip design thinking.
So this will be our starting code.
To know more about how we arrived here, go over past article.
The final code is here.
Context API
Context API lets any component within the Context Provider work with global data and functions.
The TodoProvider function is created in the src/todoContext.tsx file.
const TodoProvider = ({children}: {children: ReactNode}) => {
const [tasks, setTasks] = useState<Task[]>([
{
pending: true,
description: 'Be a pro in React Native',
},
]);
// functions
const addTodo = (todo: string) => {
let task = {
pending: true,
description: todo,
};
setTasks([...tasks, task]);
};
const updateTodoStatus = (index: number) => {
const updatedTasks = [...tasks];
updatedTasks[index].pending = !updatedTasks[index].pending;
setTasks(updatedTasks);
};
const updateTodoDetails = (index: number, description: string) => {
const updatedTasks = [...tasks];
updatedTasks[index].description = description;
setTasks(updatedTasks);
};
const deleteTodo = (index: number) => {
const updatedTasks = [...tasks];
updatedTasks.splice(index, 1);
setTasks(updatedTasks);
};
return (
<TodoContext.Provider
value={{
tasks,
addTodo,
updateTodoDetails,
updateTodoStatus,
deleteTodo,
}}>
{children}
</TodoContext.Provider>
);
};
This functions encapsulates the App Navigator in App.tsx.
<TodoProvider>
<AppNavigator />
</TodoProvider>
To get access to the data and functions, we call the context in the component we need.
const {tasks} = useContext(TodoContext) as TodoContextType;
const {updateTodoStatus} = useContext(TodoContext) as TodoContextType;
This is the type it needs.
export type TodoContextType = {
tasks: Task[];
addTodo: (todo: string) => void;
updateTodoDetails: (index: number, description: string) => void;
updateTodoStatus: (index: number) => void;
deleteTodo: (index: number) => void;
};
Component optimisations
Now that we have a central store of data, we can make smaller reusable components.
Like...
const CustomCheckBox = ({item, index}: {item: Task; index: number}) => {
const {updateTodoStatus} = useContext(TodoContext) as TodoContextType;
return (
<Checkbox.Android
status={!item.pending ? 'checked' : 'unchecked'}
onPress={() => updateTodoStatus(index)}
color="#4F4F4F"
/>
);
};
Next Steps
In this problem we are using many functions in Context API to manage the data.
This is not maintainable.
We can optimise it using a reducer function.
Follow this guide to modify it.