React Hooks + Mobx =>无效的挂钩调用。挂钩只能在功能组件的主体内部调用

时间:2020-03-10 16:53:16

标签: reactjs react-hooks mobx

我有一个React Native应用, 在这里,我使用mobx(“ mobx-react”:“ ^ 6.1.8”)并做出反应。

我得到错误: 无效的挂接调用。挂钩只能在功能组件的主体内部调用

存储index.js

import { useContext } from "react";
import UserStore from "./UserStore";
import SettingsStore from "./SettingsStore";


const useStore = () => {
  return {
    UserStore: useContext(UserStore),
    SettingsStore: useContext(SettingsStore),
  };
};

export default useStore;

helper.js旧

    import React from "react";
    import useStores from "../stores";

    export const useLoadAsyncProfileDependencies = userID => {
  const { ExamsStore, UserStore, CTAStore, AnswersStore } = useStores();
  const [user, setUser] = useState({});
  const [ctas, setCtas] = useState([]);
  const [answers, setAnswers] = useState([]);

  useEffect(() => {
    if (userID) {
      (async () => {
        const user = await UserStore.initUser();
        UserStore.user = user;
        setUser(user);
      })();
      (async () => {
        const ctas = await CTAStore.getAllCTAS(userID);
        CTAStore.ctas = ctas;
        setCtas(ctas);
      })();
      (async () => {
        const answers = await AnswersStore.getAllAnswers(userID);
        UserStore.user.answers = answers.items;
        AnswersStore.answers = answers.items;
        ExamsStore.initExams(answers.items);
        setAnswers(answers.items);
      })();
    }
  }, [userID]);
};

屏幕

import React, { useEffect, useState, useRef } from "react";
import {
  View,
  Dimensions,
  SafeAreaView,
  ScrollView,
  StyleSheet
} from "react-native";
import {
  widthPercentageToDP as wp,
  heightPercentageToDP as hp
} from "react-native-responsive-screen";

import { observer } from "mobx-react";
import useStores from "../../stores";
import { useLoadAsyncProfileDependencies } from "../../helper/app";
const windowWidth = Dimensions.get("window").width;

export default observer(({ navigation }) => {
  const {
    UserStore,
    ExamsStore,
    CTAStore,
    InternetConnectionStore
  } = useStores();
  const scrollViewRef = useRef();

  const [currentSlide, setCurrentSlide] = useState(0);

  useEffect(() => {
    if (InternetConnectionStore.isOffline) {
      return;
    }
    Tracking.trackEvent("opensScreen", { name: "Challenges" });
    useLoadAsyncProfileDependencies(UserStore.userID);
  }, []);

  React.useEffect(() => {
    const unsubscribe = navigation.addListener("focus", () => {
      CTAStore.popBadget(BadgetNames.ChallengesTab);
    });
    return unsubscribe;
  }, [navigation]);

  async function refresh() {
    const user = await UserStore.initUser(); //wird das gebarucht?
    useLoadAsyncProfileDependencies(UserStore.userID);
    if (user) {
      InternetConnectionStore.isOffline = false;
    }
  }

  const name = UserStore.name;

  return (
    <SafeAreaView style={styles.container} forceInset={{ top: "always" }}>

    </SafeAreaView>
  );
});

现在,当我调用useLoadAsyncProfileDependencies函数时,出现此错误。

问题是我在helper.js中调用useStores

因此,当我将商店从屏幕传递给助手时,它正在工作。

export const loadAsyncProfileDependencies = async ({
  ExamsStore,
  UserStore,
  CTAStore,
  AnswersStore
}) => {
  const userID = UserStore.userID;
  if (userID) {
    UserStore.initUser().then(user => {
      UserStore.user = user;
    });
    CTAStore.getAllCTAS(userID).then(ctas => {
      console.log("test", ctas);
      CTAStore.ctas = ctas;
    });
    AnswersStore.getAllAnswers(userID).then(answers => {
      AnswersStore.answers = answers.items;
      ExamsStore.initExams(answers.items);
    });
  }
};

有更好的方法吗?而不是通过商店。 这样我就可以在函数中使用此功能?

1 个答案:

答案 0 :(得分:0)

如错误所示,您只能在功能组件的根内部使用钩子,而useLoadAsyncProfileDependencies从技术上讲是自定义钩子,因此您不能在类组件中使用它。

https://reactjs.org/warnings/invalid-hook-call-warning.html


编辑:如前所述,在显示了app.js的代码之后,钩子调用只能在函数组件或自定义钩子的根目录上进行。您需要重新连接代码以使用自定义钩子。

请参阅:https://reactjs.org/docs/hooks-rules.html

  1. 您应该返回_handleAppStateChange的值,以使useEffect的值作为根组件中依赖的值将按预期正常工作,只有在值更改后才能运行。您还需要将其重写为自定义钩子,以便可以在内部调用钩子。

  2. doTasksEveryTimeWhenAppWillOpenFromBackgorunddoTasksEveryTimeWhenAppGoesToBackgorund也应写为自定义钩子,以便您可以在内部调用useLoadAsyncProfileDependencies

  3. 以一种实用的方式编写这些钩子,以便在不违反钩子规则的情况下,根据需要隔离特定任务和链式钩子。像这样的东西:

const useGetMyData = (params) => {
    const [data, setData] = useState()

    useEffect(() => {
        (async () => {
            const apiData = await myApiCall(params)
            setData(apiData)
        })()
    }, [params])

    return data
}

然后,您可以根据需要调用该自定义钩子,而不会受到侵犯,例如:



const useShouldGetData = (should, params) => {
    if (should) {
        return useGetMyData()
    }

    return null
}

const myApp = () => {
    const myData = useShouldGetData(true, {id: 1})

    return (
        <div>
            {JSON.stringify(myData)}
        </div>
    )
}