【问题标题】:React Native fetch before render components在渲染组件之前 React Native fetch
【发布时间】:2020-09-13 02:10:32
【问题描述】:

我正在创建一个 Reat Native 应用程序,该应用程序连接到它从中获取数据的 API。

我正在使用 React Navigation 来处理导航。该应用程序有一个堆栈导航器和一个底部选项卡导航器。 StackNavigator 有 4 个屏幕:

  • SignupScreen 负责创建帐户;
  • LoginScreen 用于手动登录;
  • SplashScreen 检查本地令牌并自动登录用户;
  • LoadingScreen 触发对 API 的初始 fetch 调用,将响应存储在 state 中并导航到 MainFlow 屏幕;
  • 包含TabNavigatorMainFlow 屏幕。

TabNavigator 有两个屏幕,FeedScreenAccountMore,其中初始屏幕是 FeedScreen

注册/登录/本地流程都运行良好。

问题:一旦用户成功登录,LoadingScreen 就会触发 API 调用,但 MainFlow 组件会在数据处于状态之前呈现。因为MainFlow中的组件需要数据,所以会报错。如何仅在数据存在后才呈现 FeedScreen 组件?

LoadingScreen 中,我正在从上下文对象QuestionContext 触发对useEffect 的API 调用:

const LoadingScreen = ({ navigation }) => {
  const [loading, setLoading] = useState(true);
  const { state: authState } = useContext(AuthContext);
  const { getQuestionsForUser, getAllQuestions } = useContext(QuestionContext);

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

  return (
    <View style={styles.container}>
      <YonStatusBar backgroundColor="#310B3B" />
      <Image source={splashLogo} containerStyle={styles.splashLogo} />
      <ActivityIndicator />
    </View>
  );
};

export default LoadingScreen;

getAllQuestionsQuestionContext 中的一个函数,它进行 API 调用并导航到 FeedScreen

const getAllQuestions = (dispatch) => {
  return async () => {
    try {
      const token = await AsyncStorage.getItem('token');
      const config = { headers: { Authorization: `Bearer ${token}` } };
      const response = await yonyonApi.get(`/questions`, config);
      dispatch({ type: 'GET_ALL_QUESTIONS', payload: response.data });
      RootNavigation.navigate('MainFlow');
    } catch (e) {
      console.log(e);
    }
  };
};

getAllQuestions 工作正常:API 调用成功,我可以看到响应存储在 state 中。但是,它会在此之前导航到 MainFlow

最后,这是FeedScreen

const FeedScreen = () => {
  const { state: questionState } = useContext(QuestionContext);

  return (
    <ScrollView style={styles.container}>
      {console.log(questionState.questions)}
      <View style={styles.listContainer}>
        <QuestionCard />
      </View>
    </ScrollView>
  );
};

export default FeedScreen;

FeedScreen 呈现一个QuestionCard,它需要questionState 中的数据。这就是引发错误的原因:QuestionCard 在数据处于状态之前被渲染。

一旦必要的数据处于状态,我怎样才能让导航只导航到FeedScreen?或者,在数据不存在时渲染QuestionCard以外的其他内容,一旦数据在questionState中,渲染QuestionCard

【问题讨论】:

    标签: reactjs react-native react-navigation render use-effect


    【解决方案1】:

    为什么不将上下文的初始状态设置为null,如果不是null,则渲染组件?

    const [questionState, setQuestionState] = useState(null); 
    
    ...
    
    const FeedScreen = () => {
      const { state: questionState } = useContext(QuestionContext);
    
      return (
        <ScrollView style={styles.container}>
          {!!questionState?.questions && console.log(questionState.questions)}
          <View style={styles.listContainer}>
            <QuestionCard />
          </View>
        </ScrollView>
      );
    };
    
    export default FeedScreen;
    

    【讨论】:

      【解决方案2】:

      对我来说,我将使用屏幕而不是两个屏幕,如下所示:

       const FeedScreen = () => {
      
        const [loading, setLoading] = useState(true);
        const { state: authState } = useContext(AuthContext);
        const [data, setData] = useState([]);
      
      const getAllQuestions = (dispatch) => {
        return async () => {
          try {
            const token = await AsyncStorage.getItem('token');
            const config = { headers: { Authorization: `Bearer ${token}` } };
            const response = await yonyonApi.get(`/questions`, config);
            setData(response.data)
            setLoading(false)
          } catch (e) {
            console.log(e);
          }
        };
      };
        useEffect(() => {
          getAllQuestions();
        }, []);
      
            return (
              <ScrollView style={styles.container}>
                {
                  (loading)?
                   <ActivityIndicator/>
                   :
                   <View style={styles.listContainer}>
                      <QuestionCard  data={data}/>
                    </View>
                 }
              </ScrollView>
            );
          };
      
          export default FeedScreen;
      

      【讨论】:

      • 感谢您的支持。帮助。但是,这不允许我使用存储在上下文中的状态变量。我不想在我的屏幕中创建本地状态,而是使用上下文中的一个。目前,上下文负责所有异步操作,例如进行 API 调用。在渲染 QuestionCard 组件之前,如何在屏幕上等待所有这些操作完成并填充状态?谢谢
      猜你喜欢
      • 1970-01-01
      • 2020-11-10
      • 1970-01-01
      • 1970-01-01
      • 2018-04-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多