React Hooks + Mobx => Неверный вызов хука. Хуки могут быть вызваны только внутри тела компонента функции - PullRequest
0 голосов
/ 10 марта 2020

У меня есть приложение React Native, здесь я использую mobx ("mobx-реагировать": "^ 6.1.8") и реагирую на хуки.

я получаю ошибку: Неверный вызов хука. Хуки могут вызываться только внутри тела компонента функции

Индекс хранилища. 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;

помощник. 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, я получаю эту ошибку.

Проблема в том, что я вызываю useStores в помощнике. js

так когда я передаю магазины с экрана помощнику, он работает.

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 голосов
/ 10 марта 2020

Как говорится в сообщении об ошибке, вы можете использовать только хуки внутри root функционального компонента, а ваш useLoadAsyncProfileDependencies технически является пользовательским хуком, поэтому вы не можете использовать его внутри компонента класса.

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


РЕДАКТИРОВАТЬ: Хорошо после показа кода для приложения. js, как уже упоминалось, вызовы ловушки могут быть сделаны только на верхнем уровне из функционального компонента или root нестандартного крючка. Вам нужно переписать код, чтобы использовать пользовательские перехватчики.

СМОТРИТЕ ЭТО: https://reactjs.org/docs/hooks-rules.html

  1. Вы должны вернуть значение для _handleAppStateChange поэтому ваше useEffect значение в качестве зависимости в вашем root компоненте будет работать должным образом, как и предполагалось, и должно работать только в случае изменения значения. Вам также нужно переписать это как пользовательский хук, чтобы вы могли вызывать хуки внутри.

  2. doTasksEveryTimeWhenAppWillOpenFromBackgorund и doTasksEveryTimeWhenAppGoesToBackgorund также должны быть записаны как пользовательский хук, чтобы вы могли вызвать useLoadAsyncProfileDependencies inside.

  3. функционально напишите эти хуки, чтобы вы выделяли c задачи и цепные хуки, как sh, не нарушая правил хуков. Примерно так:

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

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

    return data
}

Затем вы можете вызывать этот пользовательский хук так же, как вы будете sh без нарушения, например:



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

    return null
}

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

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