.функция карты не работает с React Native

#reactjs #react-native #array.prototype.map

Вопрос:

У меня есть .map() функция с кодом JSX внутри. Хотя JSX не выполняет рендеринг. Это происходит только после того, как я сохраню файл. Я использую expo (React Native).

Вот мой код:

 import React, { useEffect, useState } from "react";
import * as SecureStore from "expo-secure-store";
import { View, Text, ActivityIndicator } from "react-native";
import { Button } from "react-native-elements";

const Receipts = ({ navigation }) => {
  const [receipts, setReceipts] = useState([]);
  const [loading, setLoding] = useState(true);
  const [result, setResult] = useState({});
  const [keys, setKeys] = useState([]);
  useEffect(() => {
    const getReceiptsData = async () => {
      let token = await SecureStore.getItemAsync("token");
      console.log(token);
      fetch("https://notrealapi/api/receipts", {
        method: "GET",
        headers: {
          Authorization: `JWT ${JSON.parse(token)}`,
        },
      })
        .then((res) => res.json())
        .then((json) => {
          setReceipts(json);
          setLoding(false);
        })
        .catch((error) => console.error(error));
    };

    getReceiptsData();
    processReceipts();
  }, []);

  const processReceipts = () => {
    const dubps = [];
    const resultObj = {};
    receipts.map((item) => {
      if (dubps.includes(item.merchant_name)) {
        resultObj[item.merchant_name] =
          resultObj[item.merchant_name]   parseFloat(item.total);
      } else {
        resultObj[item.merchant_name] = parseFloat(item.total);
        dubps.push(item.merchant_name);
      }
    });
    setResult(resultObj);
    setKeys(Object.keys(resultObj));
  };

  const exportReport = async () => {
    let token = await SecureStore.getItemAsync("token");
    fetch("https://notrealapi/api/export", {
      method: "GET",
      headers: {
        Authorization: `JWT ${JSON.parse(token)}`,
      },
    })
      .then((res) => res.json())
      .then((json) => {
        console.log(json);
      })
      .catch((error) => console.error(error));
  };

  const renderSummary = () => {
    return keys.map((key) => {
      return (
        <View>
          <Text
            key={key}
            style={{
              fontSize: 15,
              fontWeight: "normal",
              paddingBottom: 50,
            }}
          >
            {`You have spent ${result[key].toString()} at ${key}`}
          </Text>
        </View>
      );
    });
  };

  return (
    <View style={{ flex: 1, alignItems: "center", justifyContent: "center" }}>
      {loading ? (
        <ActivityIndicator size="large" color="blue" />
      ) : (
        <>
          <Text style={{ fontSize: 30, fontWeight: "bold", paddingBottom: 50 }}>
            Summary:
          </Text>
          {renderSummary()}
          <Button
            type="outline"
            title="Export detailed report"
            onPress={exportReport}
          />
          <Text style={{ fontSize: 10, marginTop: 10 }}>
            *The detailed report shall be sent by email.
          </Text>
        </>
      )}
    </View>
  );
};

export default Receipts;
 

Примечание: Это действительно работает, но только когда я сохраняю файл и он обновляется с помощью интерфейса командной строки expo. Кроме того, в renderSummary() функции возникает ошибка.

Обновление: keys может быть равно ["Costco"] и result может быть равно {Costco: 69.99}

Комментарии:

1. Зачем вы используете карту, если не создаете новый массив?

2. ключи-это массив.

3. Это не очень хорошая идея-дублировать состояние. Кроме того, вы уверены, что не бежите processReceipts() до getReceiptsData() завершения?

4. Что вы подразумеваете под дублированным состоянием? Кроме того, как бы вы устранили риск getReceiptsData() бега раньше processReceipts() ?

Ответ №1:

Вы запускаетесь processReceipts() до того, как разрешится внутренняя выборка getReceiptsData() .

Обратите внимание на порядок журналов консоли в этом примере.

 import React, { useEffect, useState } from "react";

const Receipts = () => {
  const [receipts, setReceipts] = useState([]);
  const [loading, setLoding] = useState(true);
  const [result, setResult] = useState({});
  const [keys, setKeys] = useState([]);

  useEffect(() => {
    const getReceiptsData = async () => {
      fetch("https://rickandmortyapi.com/api/character/1", {
        method: "GET"
      })
        .then((res) => res.json())
        .then((json) => {
          console.log("getReceiptsData resolves");
          setReceipts(json);
          setLoding(false);
        })
        .catch((error) => console.error(error));
    };

    getReceiptsData(); // js won't wait here
    processReceipts();
  }, []);

  const processReceipts = (json) => {
    console.log("processReceipts()");
  };
  return null;
};

export default Receipts;
 

Редактирование processReceipts-выполняется-слишком-рано-рано


Вместо этого обработайте манипуляции с данными, когда выборка разрешится.

 import React, { useEffect, useState } from "react";

const Receipts = () => {
  const [loading, setLoding] = useState(true);
  const [result, setResult] = useState({});

  useEffect(() => {
    const getReceiptsData = async () => {
      fetch("https://rickandmortyapi.com/api/character/1", {
        method: "GET"
      })
        .then((res) => res.json())
        .then((json) => {
          console.log("getReceiptsData resolves");
          processReceipts(json);
          setLoding(false);
        })
        .catch((error) => console.error(error));
    };

    getReceiptsData();
  }, []);

  const processReceipts = (json) => {
    console.log("processReceipts()");
    // do some work and then setResult
  };
  return null;
};

export default Receipts;
 

Редактирование processReceipts-выполняется-слишком-рано-рано (раздвоенный)


Кроме того, по возможности избегайте хранения состояния, полученного из другого состояния. Вы должны либо преобразовать полезную нагрузку сервера в полезные данные:

  • когда вы получите полезную нагрузку, установите ее в состояние или
  • когда вы выполняете рендеринг