#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;
Вместо этого обработайте манипуляции с данными, когда выборка разрешится.
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;
Кроме того, по возможности избегайте хранения состояния, полученного из другого состояния. Вы должны либо преобразовать полезную нагрузку сервера в полезные данные:
- когда вы получите полезную нагрузку, установите ее в состояние или
- когда вы выполняете рендеринг