reactjs 多次使用带有react native的上下文文件中的效果

jk9hmnmh  于 2023-03-08  发布在  React
关注(0)|答案(2)|浏览(94)

我有一个react原生应用程序。我有两个api调用:一个用于主页,另一个用于从主页导航到另一个组件。但问题是,如果应用程序首次加载,两个api调用都会被调用。但不必如此--当应用程序首次加载时,只需调用负责构建主页的api调用。
所以我有一个服务:

export const fetchCategoryData = async () => {
    try {
        const response = await fetch("http://192.168.1.68:8000/api/categories/main_groups/", {
            method: "GET",
            headers: {
                Accept: "application/json",
                "Content-Type": "application/json",
            },
        });
        if (!response.ok) {
            throw new Error("Network response was not ok");
        }

        return await response.json();
    } catch (error) {
        console.error("There was a problem with the fetch operation:", error);
        throw error;
    }
};

export const fetchSubCategoryData = async () => {
    try {
        const response = await fetch("http://192.168.1.68:8000/api/categories/2/", {
            method: "GET",
            headers: {
                Accept: "application/json",
                "Content-Type": "application/json",
            },
        });
        if (!response.ok) {
            throw new Error("Network response was not ok");
        }

        return await response.json();
    } catch (error) {
        console.error("There was a problem with the fetch operation:", error);
        throw error;
    }
};

以及上下文:

export const CategoryContext = createContext();

export const CategoryContextProvider = ({ children }) => {
    const [categoryList, setCategoryList] = useState([]);
    const [subCategoryList, setSubCategoryList] = useState([]);
    const [loading, setLoading] = useState(false);
    const [error, setError] = useState(null);
    const [] = useState([]);

    const retrieveCategories = () => {
        setLoading(true);
        setTimeout(() => {
            fetchCategoryData()
                .then((results) => {
                    setLoading(false);
                    setCategoryList(results);
                })
                .catch((err) => {
                    setLoading(false);
                    setError(err);
                });
        });
    };

    const retrieveSubCategories = () => {
        setLoading(true);
        setTimeout(() => {
            fetchSubCategoryData()
                //.then(subCategoryTransform)
                .then((results) => {
                    setLoading(false);
                    setSubCategoryList(results.subcategories);
                })
                .catch((err) => {
                    setLoading(false);
                    setError(err);
                });
        });
    };

    useEffect(() => {
        retrieveCategories();
    }, []);

    useEffect(() => {
        retrieveSubCategories();
    }, []);

    return (
        <CategoryContext.Provider
            value={{
                lue={{
                categoryList,
                subCategoryList,
                loading,
                error,
            }}>
            {children}
        </CategoryContext.Provider>
    );
};

因此,当应用程序第一次加载时,只需加载此函数:但是当我查看后端时。我还看到这个函数被调用:检索子类别。
并且这是用户可以导航到API调用的组件的组件:必须触发fetchSubCategoryData:

export const CategoryScreen = ({ navigation }) => {
    const { loading, error, categoryList } = useContext(CategoryContext);
    return (
        <SafeArea>
            {loading && (
                <LoadingContainer>
                    <ActivityIndicator animating={true} color={MD2Colors.green200} />
                </LoadingContainer>
            )}
            <Search />
            <CategoryList
                data={categoryList}
                renderItem={({ item }) => {
                    return (
                        <TouchableOpacity onPress={() => navigation.navigate("groepen", { category: item.id })}>
                            <Spacer position="bottom" size="large">
                                <CategoryInfoCard category={item} />
                            </Spacer>
                        </TouchableOpacity>
                    );
                }}
                keyExtractor={(item) => item.id}
            />
        </SafeArea>
    );
};

这是App.js文件:

export default function App() {
    const [oswaldLoaded] = useOswald({
        Oswald_400Regular,
    });

    const [latoLoaded] = useLato({
        Lato_400Regular,
        Lato_900Black,
    });

    if (!oswaldLoaded || !latoLoaded) {
        return null;
    }

    return (
        <>
            <ThemeProvider theme={theme}>
                <CategoryContextProvider>
                    <Navigation />
                </CategoryContextProvider>
            </ThemeProvider>

            <ExpoStatusBar style="auto" />
        </>
    );
}

问题:如何只加载api调用:在应用首次加载时获取CategoryData。
好吧,如果我这样做:

/* eslint-disable prettier/prettier */

import React, { useEffect, useState } from "react";
import { Text, View } from "react-native";
import { CategoryList } from "./category.screen";
import { SafeArea } from "../../../components/utility/safe-area.component";
import { Spacer } from "../../../components/spacer/spacer.component";
import { SubCategoryInfoCard } from "../components/subcategory-info-card.component";
import { TouchableOpacity } from "react-native-gesture-handler";
import { fetchSubCategoryData } from "../../../services/category/category.service";

export const SubCategoryScreen = ({ route }) => {
    const [subCatgoryList, setSubCategoryList] = useState([]);

    useEffect(() => {
        fetchSubCategoryData(route.category).then((data) => {
            setSubCategoryList(data);
        });
    }, [route.category]);

    return (
        <SafeArea>
            <CategoryList
                data={subCatgoryList}
                renderItem={({ item }) => {
                    return (
                        <TouchableOpacity onPress={() => console.log(item)}>
                            <Spacer position="bottom" size="large">
                                <SubCategoryInfoCard category={item} />
                            </Spacer>
                        </TouchableOpacity>
                    );
                }}
                keyExtractor={(item) => item.id}
            />
        </SafeArea>
    );
};

我得到这个错误:
不变违背:TaskQueue:任务出错:尝试获取超出范围索引NaN的帧

zujrkrfu

zujrkrfu1#

如果我正确理解了您的需求,您所要做的就是从上下文中删除以下行:

// remove
    useEffect(() => {
        retrieveSubCategories();
    }, []);

然后在从主屏幕导航或返回焦点效果时调用retrieveSubCategories:

useFocusEffect(useCallback(() => {
    return retrieveSubcategories;
  }, []));

这将在主屏幕模糊时调用该函数。从上下文中删除该函数将防止在上下文装载时调用该函数。

qjp7pelc

qjp7pelc2#

一个可能的解决方案是当你导航到子类别/细节页面时只调用子类别的API,当useEffect改变时使用useEffect来获取类别,我使用了本地状态,但是你显然可以使用上下文中的setState来实现。

export const SubCategoryScreen = ({ route }) => {
  const [subCatgoryList, setSubCategoryList] = useState([]);

  useEffect(() => {
    fetchSubCategoryData(route.category).then((data) => {
      setSubCategoryList(data);
    });
  }, [route.category]);

  return (
    <View>
      <Text>Sub Catgories</Text>
      <CategoryList
        data={subCatgoryList}
        renderItem={({ item }) => {
          return (
            <TouchableOpacity onPress={() => console.log(item)}>
              <Spacer position="bottom" size="large">
                <CategoryInfoCard category={item} />
              </Spacer>
            </TouchableOpacity>
          );
        }}
        keyExtractor={(item) => item.id}
      />
    </View>
  );
};

id传递给fetchSubCategoryData以使其更具动态性

export const fetchSubCategoryData = async (id) => {
  try {
    const response = await fetch(
      `http://192.168.1.68:8000/api/categories/${id}`,
      {
        method: "GET",
        headers: {
          Accept: "application/json",
          "Content-Type": "application/json",
        },
      }
    );
    if (!response.ok) {
      throw new Error("Network response was not ok");
    }

    const data = await response.json();
    return data;
  } catch (error) {
    console.error("There was a problem with the fetch operation:", error);
    throw error;
  }
};

相关问题