I’m working on a React Native app and using context to manage categories. However, I’m encountering an issue where the context value doesn’t update the state variable in time, leading to a render error when trying to dynamically render Picker.Item components.
Here’s my simplified context and state setup:
_layout.tsx
import React from 'react';
import { Slot } from 'expo-router';
import { CategoriesProvider } from '@/context/categoriesContext';
const AppLayout = () => {
return (
<CategoriesProvider>
<Slot />
</CategoriesProvider>
);
};
export default AppLayout;
categoriesContext.tsx
import React, { useState, createContext, useEffect } from "react";
import { fetchData } from "@/functions/api";
interface CategoryContextType {
categories: {
loading: boolean;
error: any;
[key: string]: any;
};
setCategories: React.Dispatch<React.SetStateAction<{
loading: boolean;
error: any;
[key: string]: any;
}>>;
}
const CategoryContext = createContext<CategoryContextType | undefined>(undefined);
const CategoriesProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
const [categories, setCategories] = useState<{loading: boolean, error: any, [key: string]: any}>({ loading: true, error: null });
useEffect(() => {
const getCategories = async () => {
try {
const response = await fetchData(
'/public/',
{
request: 'getCategories',
columns: ['*'],
}
);
setCategories(prev => ({ ...prev, response: response, loading: false }));
} catch (err: unknown) {
if (err instanceof Error) setCategories(prev => ({ ...prev, error: err.message }));
else setCategories(prev => ({ ...prev, error: "An unknown error occurred" }));
}
};
getCategories();
}, []);
return (
<CategoryContext.Provider value={{ categories, setCategories }}>
{children}
</CategoryContext.Provider>
);
};
export { CategoryContext, CategoriesProvider };
export type { CategoryContextType };
header.tsx
// header.tsx
import React, { useEffect, useState, useContext } from 'react';
import { View } from 'react-native';
import { Picker } from '@react-native-picker/picker';
import { CategoryContext } from '@/context/categoriesContext';
interface CategoriesState {
loading: boolean;
error?: any;
data?: object;
}
export default function Header() {
const [categories, setCategories] = useState<CategoriesState>({ loading: true });
const categoryContext = useContext(CategoryContext);
const [formData, setFormData] = useState({ category: '', search: '' });
useEffect(() => {
if (categoryContext) {
setCategories(prev => ({ ...prev, data: categoryContext.categories.response, loading: false }));
} else {
setCategories({ loading: true });
}
}, [categoryContext]);
return (
<View>
<Picker
selectedValue={formData.category}
onValueChange={(itemValue) => setFormData((prev) => ({ ...prev, category: itemValue }))}
>
{categories.loading ? (
<Picker.Item label="Loading..." value="loading" />
) : (
categories.data && (
Object.entries(categories.data).map(([key, value]) => (
<Picker.Item key={key} label={value.category_name} value={value.category_id} />
))
)
)}
</Picker>
</View>
);
}
Issue
The state update seems to lag behind the context value update, causing the following error during rendering:
No overload matches this call.
Overload 1 of 2, '(props: PickerProps<string> | Readonly<PickerProps<string>>): Picker<string>', gave the following error.
Type 'Element | { Object: ObjectConstructor; "": any; } | undefined' is not assignable to type 'ReactNode'.
Object literal may only specify known properties, and 'Object' does not exist in type 'ReactElement<any, string | JSXElementConstructor<any>> | ReactFragment | ReactPortal'.
Overload 2 of 2, '(props: PickerProps<string>, context: any): Picker<string>', gave the following error.
Type 'Element | { Object: ObjectConstructor; "": any; } | undefined' is not assignable to type 'ReactNode'.
Object literal may only specify known properties, and 'Object' does not exist in type 'ReactElement<any, string | JSXElementConstructor<any>> | ReactFragment | ReactPortal'.
Expected Behavior
I expect to update the categories state variable with the context value and render Picker.Item components for each category.
Actual Behavior
The state variable categories doesn’t update in time, causing a render error.
Question
How can I ensure the state variable categories is updated in time with the context value to avoid rendering errors in React Native? Are there any best practices or alternative approaches to handle this situation?