I'm trying to do an app where you can create some projects, to do so on the main screen ("ProjectsScreen") I have a <ProjectsList/>
component that takes the data from fetchProjects when rendered.
The problem comes after a new project is created. To create a project im navigating to "CreateProjectScreen" where, when the new project is created, I'm nagivating back to "ProjectsScreen" the <ProjectsList/>
is not updating with the new data.
The new data after creating a project its saved correctly but the FlatList
is not refreshed, at this moment I've achieved so with a scroll-to-refresh
How can I refresh the FlatList
when I am back on ProjectScreen
Thats the structure of the code
-ProjectsScreen
--ProjectsList
---FetchProjects
-CreateProjectScreen
I add the code bellow
ProjectsScreen
:
const ProjectsScreen = ({ navigation }) => {
const [apiResult, setApiResult] = useState(null);
const [apiError, setApiError] = useState(null);
const { reloadProjects } = useProjects();
const { t } = useTranslation();
useEffect(() => {
reloadProjects();
}, []);
return (
<SafeAreaView style={styles.container}>
<Text style={styles.title}>{t("title.projects")}</Text>
<View style={styles.viewContainer}>
<View style={styles.projectsContainer}>
<ProjectsList navigation={navigation} />
</View>
<View style={styles.buttonContainer}>
<StyledButton
whiteBtn={true}
title={t("buttons.new_project")}
navigation={navigation}
onPress={() => navigation.navigate("CreateProject")}
/>
</View>
</View>
</SafeAreaView>
);
};
Project list component:
const ProjectsList = ({ navigation }) => {
const { projects, isLoading, reloadProjects } = useProjects();
const [refreshing, setRefreshing] = useState(false);
const onRefresh = useCallback(() => {
setRefreshing(true);
setTimeout(() => {
reloadProjects();
setRefreshing(false);
}, 2000);
}, []);
return (
<View style={styles.container}>
{isLoading ? (
<ActivityIndicator size="large" colors={COLORS.primary} />
) : (
<FlatList
data={projects}
keyExtractor={(project) => project.uuid}
renderItem={({ item: project }) => (
<TouchableOpacity
onPress={() => navigation.navigate("Upload", { project })}
>
<View style={styles.projectContainer}>
<View
style={{
flexDirection: "row",
justifyContent: "space-between",
}}
>
<Text style={styles.title}>{project.name}</Text>
<TouchableOpacity
onPress={() => handleDeletePress(project, reloadProjects)}
>
<Image style={{ marginTop: 12 }} source={icons.del} />
</TouchableOpacity>
</View>
<Text style={styles.description}>{project.description}</Text>
{/* <Text>UUID: {project.uuid}</Text> */}
{project.models && project.models.length > 0 && (
<View style={styles.modelsContainer}>
{/* <Text style={styles.modelsHeader}>Models:</Text> */}
<FlatList
data={project.models}
keyExtractor={(model) => model.uuid}
renderItem={({ item: model }) => (
<View style={styles.modelContainer}>
{/* <LinearGradient colors={['#FF4D00', '#FF00D6']} style={styles.gradient}> */}
<Text style={styles.modelsName}>{model.name}</Text>
<Text style={styles.modelsDesc}>
{model.description}
</Text>
{/* <Text>UUID: {model.uuid}</Text> */}
{/* </LinearGradient> */}
</View>
)}
showsHorizonralScrollIndicator={false}
horizontal
/>
</View>
)}
</View>
</TouchableOpacity>
)}
showsVerticalScrollIndicator={false}
refreshing={refreshing} // Added pull to refesh state
onRefresh={onRefresh} // Added pull to refresh control
ListEmptyComponent={
<Text style={{ fontSize: SIZES.medium }}>
{t("error.projects")} :( {"\n\n"}
{t("error.refresh")}
</Text>
}
/>
)}
</View>
);
};
fetchProjects:
const useProjects = () => {
const [projects, setProjects] = useState([]);
const [isLoading, setIsLoading] = useState(false);
const fetchProjects = async () => {
setIsLoading(true);
const token = await AsyncStorage.getItem("access_token");
const config = {
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
Accept: "application/json",
},
};
try {
const response = await axios.get("http:/asof/v1/projects/", config);
if (!response.status === 200) {
throw new Error(`HTTP error! Status: ${response.status}`);
} else {
setProjects(response.data);
}
} catch (error) {
console.log(error);
console.error("Error fetching repositories:", error.message);
} finally {
setIsLoading(false);
}
};
useEffect(() => {
fetchProjects();
}, []);
return { projects, isLoading, reloadProjects: fetchProjects };
};
export default useProjects;
CreateProjectScreen:
const initialValues = {
name: "",
description: "",
models_uuid: [],
};
const sendApi = async (
values,
setApiResult,
setApiError,
{ navigation },
reloadProjects
) => {
try {
// Obtén el token de AsyncStorage
const token = await AsyncStorage.getItem("access_token");
// Configuración de la solicitud
const config = {
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
Accept: "application/json",
},
};
// Datos del cuerpo de la solicitud
const data = {
name: values.name,
description: values.description,
models_uuid: values.models_uuid,
};
// Realiza la solicitud POST
const response = await axios.post("http://asof/v1/projects/", data, config);
// Maneja la respuesta
if (response.status === 201) {
console.log("Project created successfully");
Alert.alert("Project created successfully");
navigation.navigate("ProjectsScreen");
reloadProjects();
// Si es necesario, puedes manejar el resultado de la API
setApiResult(response.data);
} else {
console.log(response);
setApiError("Error al crear el proyecto");
}
} catch (error) {
setApiError(error.message);
console.log("Error en la solicitud POST:", error);
}
};
function CreateProjectScreen({ navigation }) {
const [apiResult, setApiResult] = useState(null);
const [apiError, setApiError] = useState(null);
const { login } = useContext(AuthContext);
const { reloadProjects } = useProjects(); // Obtén reloadProjects del hook useProjects
const [selectedModelUUIDs, setSelectedModelUUIDs] = useState([]);
const { t } = useTranslation();
const handleModelsSelect = (modelUUIDs) => {
setSelectedModelUUIDs(modelUUIDs);
console.log("Modelos seleccionados: ", selectedModelUUIDs);
};
return (
<SafeAreaView style={styles.container}>
<Text style={styles.title}>{t("title.create")}</Text>
<Formik
validationSchema={ProjectValidationSchema}
initialValues={initialValues}
onSubmit={async (values) => {
values.models_uuid = selectedModelUUIDs;
console.log(values);
console.log("Submitting project:", values);
await sendApi(
values,
setApiResult,
setApiError,
{ navigation },
reloadProjects
);
}}
>
{({ values, handleChange, handleSubmit }) => {
const { name, description, password, repeatPassword } = values;
return (
<View style={styles.container}>
<Text style={styles.text}>{t("name")}</Text>
<FormikInputValue
value={name}
onChangeText={handleChange("name")}
name="name"
placeHolder={t("name")}
image={icons.user}
/>
<Text style={styles.text}>{t("description")}</Text>
<FormikInputValue
value={description}
onChangeText={handleChange("description")}
name="description"
placeHolder={t("description")}
image={icons.mail}
/>
<ModelsList onModelsSelect={handleModelsSelect} />
<View style={styles.loginButton}>
{apiError && (
<Text style={{ color: "#ff0000" }}>
{t("error.api_error")}: {apiError}
</Text>
)}
<StyledButton
onPress={handleSubmit}
title={t("buttons.create")}
whiteBtn={true}
/>
</View>
</View>
);
}}
</Formik>
</SafeAreaView>
);
}
I'm successfully getting the new data after adding anew project but no clue on how to refresh the component from main screen.
You can use useFocusEffect and useCallback to re-refetch data everytime screen is in focus.
useFocusEffect(
useCallback(() => {
refetchSomeData();
}, []),
);