【问题标题】:React Hooks + Mobx => Invalid hook call. Hooks can only be called inside of the body of a function componentReact Hooks + Mobx => 无效的钩子调用。 Hooks 只能在函数组件的主体内部调用
【发布时间】:2020-06-22 15:07:19
【问题描述】:

我有一个 React Native 应用程序, 这里我使用 mobx ("mobx-react": "^6.1.8") 和 react hooks。

我得到错误: 无效的挂钩调用。 Hooks 只能在函数组件内部调用

存储 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);
    });
  }
};

有没有更好的方法?而是通过商店。 这样我就可以在函数中使用这个函数了?

【问题讨论】:

  • 你怎么打电话给useLoadAsyncProfileDependencies?这往往发生在从事件处理程序调用钩子时,而不是在渲染期间。
  • 组件函数的第一行。
  • Const someComponent = () => { useLoadAsyncProfileDeps... }
  • 更新了根帖中的代码

标签: reactjs react-hooks mobx


【解决方案1】:

正如错误所说,您只能在功能组件的根目录中使用钩子,而您的 useLoadAsyncProfileDependencies 在技术上是自定义钩子,因此您不能在类组件中使用它。

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


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

看到这个:https://reactjs.org/docs/hooks-rules.html

    1234563您还需要将其重写为自定义钩子,以便您可以在内部调用钩子。
  1. doTasksEveryTimeWhenAppWillOpenFromBackgorund 和 doTasksEveryTimeWhenAppGoesToBackgorund 也应该写成自定义钩子,这样你就可以在里面调用useLoadAsyncProfileDependencies。

  2. 以功能性的方式编写这些钩子,以便您在不违反钩子规则的情况下根据需要隔离特定任务和链接钩子。像这样:

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>
    )
}

【讨论】:

  • 这不是一个类。 App.js 和 navigator 是函数组件
  • 那你能给我们看看这些代码吗?用我们现在拥有的东西,我们真的无处可去。
  • 我更新了问题。非常感谢您的帮助。
猜你喜欢
  • 2019-09-07
  • 1970-01-01
  • 2021-05-05
  • 2021-02-08
  • 2021-03-30
  • 2021-10-18
  • 1970-01-01
  • 2020-11-20
  • 2021-07-12
相关资源
最近更新 更多