Невозможно получить значение из локального хранилища внутри функции без преобразования в функцию asyn c - PullRequest
0 голосов
/ 07 февраля 2020

Я сделал оболочку для функции выборки для своих вызовов API в реагирующем языке. Я не хочу передавать токен JWT каждый раз, когда я выполняю вызов API, поэтому я подумал, что выборка его из оболочки обернется для меня, но я не могу заставить его работать из-за асин c природы ...

useFetch. js

// import qs from "querystring";
import { getUserAuthToken } from "../storage";

const responseChecker = async (response) => {
  let error = "";
  let data = {};
  let statusCode = null;
  if (!response.ok) {
    error = "Something went wrong";
    statusCode = response.status;
  } else {
    statusCode = response.status;
    data = await response.json();
  }
  return { statusCode, error, data };
};

const fetchAuthToken = getUserAuthToken();

const useFetch = (baseURL, authHeader = null) => {
  console.log(fetchAuthToken);
  **//Cannot get this token in time for the API call ^**
  const defaultHeader = {
    Accept: "application/json",
    "Content-Type": "application/x-www-form-urlencoded",
    key: "1c419c7e-3a34-49f0-9192-b48d4534dff3",
    Authorization: authHeader ? authHeader :fetchAuthToken,
  };

  const customFetch = (
    url,
    method = "GET",
    body = false,
    headers = defaultHeader,
  ) => {
    const options = {
      method,
      headers,
      credentials: "include",
    };
    if (body) options.body = body;
    return fetch(url, options);
  };
  const get = async (endpoint) => {
    const url = `${baseURL}${endpoint}`;
    const response = await customFetch(url, "GET");
    return responseChecker(response);
  };
  const post = async (endpoint, body = {}) => {
    const url = `${baseURL}${endpoint}`;
    const response = await customFetch(url, "POST", body);
    return responseChecker(response);
  };
  const put = async (endpoint, body = {}) => {
    const url = `${baseURL}${endpoint}`;
    const response = await customFetch(url, "PUT", body);
    return responseChecker(response);
  };
  return {
    get,
    post,
    put,
  };
};
export default useFetch;

хранилище. js

import AsyncStorage from "@react-native-community/async-storage";
export const getUserAuthToken = async () => {
  try {
    const userToken = await AsyncStorage.getItem("userAuthToken");
    return userToken;
  } catch (e) {
    console.log("error");
  }
};

exportAPI. js

import useFetch from "./fetch";
const LOCAL_IP = "192.168.0.131";
export const authAPI = (header) => useFetch(`http://${LOCAL_IP}:8000`, header);
export const activityAPI = useFetch(`http://${LOCAL_IP}:8000`);

Шаги. js

import React, { useEffect, useState } from "react";
import { Text, Platform } from "react-native";
import { CardXLarge } from "../../../components/Cards/";
import fitnessKitApis from "../../../utilities/fitnessKits";
import { activityAPI } from "../../../utilities/apis";

const StepCard = (props) => {
  const fetchStepsFromFitnessKits = async () => {
    if (Platform.OS === "android") {
      await fitnessKitApis.historicSteps().then((res) => {
        setSteps(res);
      });
    } else {
      await fitnessKitApis.historicSteps((result) => setSteps(result));
    }
  };

  const [steps, setSteps] = useState(0);

  useEffect(() => {
    fetchStepsFromFitnessKits();
    const requestParams = { date: new Date(), steps };
    const { data, statusCode, error } = activityAPI.get(
      "/v1/user/steps/",
      requestParams,
    );
    // console.log(data, statusCode, error);
  }, [steps]);
  return (
    <CardXLarge>
      <Text>{steps}</Text>
    </CardXLarge>
  );
};

export default StepCard;

Я знаю, что могу передать authHeader из компонента, но это приведет к добавлению 2-3 строк кода в каждый компонент, что не очень удобно. Спасибо

Ответы [ 3 ]

0 голосов
/ 07 февраля 2020
...
const fetchAuthToken = getUserAuthToken();
...

Ваш getUserAuthToken является асинхронной функцией, и здесь она не ожидается. Чтобы гарантировать, что асинхронный вызов завершен, вы должны дождаться его или использовать обратные вызовы, как предложено @HungrySoul.

Вы не можете ждать чего-то вне асинхронной функции.

Решение, которое я бы предложил, заключается в создании class UseFetch и передаче аргументов через конструктор. Аргументом здесь является токен JWT, который вы получаете от AsyncStorage.

Кроме того, еще одна вещь, которую можно сделать, и это хорошая практика - используйте redux для управления состоянием и хранения токена JWT , Вы можете посмотреть на это. Это займет немного больше времени, но сделает ваш код более элегантным.

Редактировать: Или вы можете попробовать что-то вроде этого.

Имейте в виду, что вам нужно дождаться выполнения обещаний, прежде чем использовать обещанное.

Здесь мы используем замыкание. Вам нужно будет передать аргумент (async function) useFetchBuilder. Эта функция будет ожидаемой и предоставит JWT. Вы можете использовать getUserAuthToken для этой цели.

Имейте в виду, что перед использованием этой функции вы должны использовать ожидание или ожидание разрешения обещания. Проблема может быть где-то еще в вашем коде - возможно, методы жизненного цикла.

Надеюсь, это помогло.

const responseChecker = async (response) => {
  let error = "";
  let data = {};
  let statusCode = null;
  if (!response.ok) {
    error = "Something went wrong";
    statusCode = response.status;
  } else {
    statusCode = response.status;
    data = await response.json();
  }
  return { statusCode, error, data };
};


const useFetchBuilder = async (userTokenProvider) => {
  const userToken = await userTokenProvider();

  return (baseURL, authHeader = null) => {

    const defaultHeader = {
      Accept: "application/json",
      "Content-Type": "application/x-www-form-urlencoded",
      key: "1c419c7e-3a34-49f0-9192-b48d4534dff3",
      Authorization: authHeader ? authHeader : userToken,
    };

    const customFetch = (
      url,
      method = "GET",
      body = false,
      headers = defaultHeader,
    ) => {
      const options = {
        method,
        headers,
        credentials: "include",
      };
      if (body) options.body = body;
      return fetch(url, options);
    };
    const get = async (endpoint) => {
      const url = `${baseURL}${endpoint}`;
      const response = await customFetch(url, "GET");
      return responseChecker(response);
    };
    const post = async (endpoint, body = {}) => {
      const url = `${baseURL}${endpoint}`;
      const response = await customFetch(url, "POST", body);
      return responseChecker(response);
    };
    const put = async (endpoint, body = {}) => {
      const url = `${baseURL}${endpoint}`;
      const response = await customFetch(url, "PUT", body);
      return responseChecker(response);
    };
    return {
      get,
      post,
      put,
    };
  };
}

export default useFetchBuilder;
0 голосов
/ 08 февраля 2020

Я переместил функцию getUserAuthToken вниз к каждой функции метода запроса в функции useFetch, где я могу ожидать ответа. Тогда все это работало отлично. Также я мог бы использовать getUserAuthToken, но использование AsyncStorage.getItem кажется намного чище

измененный выбор. js

// import qs from "querystring";
import AsyncStorage from "@react-native-community/async-storage";

const responseChecker = async (response) => {
  let error = "";
  let data = {};
  let statusCode = null;
  if (!response.ok) {
    error = "Something went wrong";
    statusCode = response.status;
  } else {
    statusCode = response.status;
    data = await response.json();
  }
  return { statusCode, error, data };
};

const useFetch = (baseURL, authHeader = null) => {
  const defaultHeader = {
    Accept: "application/json",
    // "Content-Type": "application/x-www-form-urlencoded",
    "Content-Type": "application/json",
    key: "1c419c7e-3a34-49f0-9192-b48d4534dff3",
    Authorization: authHeader,
  };

  const customFetch = (
    url,
    method = "GET",
    body = false,
    headers = defaultHeader,
  ) => {
    const options = {
      method,
      headers,
      credentials: "include",
    };
    if (body) options.body = JSON.stringify(body);
    return fetch(url, options);
  };
  const get = async (endpoint) => {
    await AsyncStorage.getItem("userAuthToken").then((result) => {
      defaultHeader.Authorization = result;
    });
    const url = `${baseURL}${endpoint}`;
    const response = await customFetch(url, "GET");
    return responseChecker(response);
  };
  const post = async (endpoint, body = {}) => {
    await AsyncStorage.getItem("userAuthToken").then((result) => {
      defaultHeader.Authorization = result;
    });
    const url = `${baseURL}${endpoint}`;
    const response = await customFetch(url, "POST", body);
    return responseChecker(response);
  };
  const put = async (endpoint, body = {}) => {
    await AsyncStorage.getItem("userAuthToken").then((result) => {
      defaultHeader.Authorization = result;
    });
    const url = `${baseURL}${endpoint}`;
    const response = await customFetch(url, "PUT", body);
    return responseChecker(response);
  };
  return {
    get,
    post,
    put,
  };
};
export default useFetch;

0 голосов
/ 07 февраля 2020

Если вы не хотите использовать async / await в функции для получения элементов из asyncStorage. Вы можете использовать обратный вызов или обещание вместо async / await.

Обратный вызов:

AsyncStorage.getItem('data1', (error, data1) => {
  // perform your logic here.
});

Обещание:

AsyncStorage.getItem('data1').then(data1=>{
 // perform your logic here.
}).catch(error=>{
 // handle error
})

Я лично использовал обратный вызов для getItem и работал отлично. Я не тестировал обещанную версию, но ожидаю выполнить ту же работу, что и обратный вызов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...