【发布时间】:2022-01-08 06:56:07
【问题描述】:
我有一个类似于以下的数据数组:
data = [{name: 'A', data: 1}, {name: 'B', data: 2}]
我也有类似以下的代码:
function ReportComponent({ data }) {
return data.map((datum) => (
<Typography>
{datum.name}: {datum.data}
</Typography>
));
}
被调用
function ReportBox({ component }) {
const { data } = useFetchHook(component.urls)
// data returns exactly as expected, an array of objects
return (
<Box>
<Typography>
{component.title}
</Typography>
{data !== null && <ReportComponent data={data} />}
</Box>
);
}
我的问题是,当我运行应用程序时,我只能从我的数据中得到一个输出(当我 console.log(data) 它返回我上面显示的数据时),要么 答:1 或 B:2。我希望组件中都存在两者。有什么建议吗?
---- 更新---- 使用Fetch函数
import { useState, useEffect } from 'react';
function useFetch(urls) {
const [data, setData] = useState(null);
const [error, setError] = useState(null);
useEffect(() => {
let i = urls.length - 1;
const result = [];
while (i >= 0) {
const abortCont = new AbortController();
console.log(`url ${i}`);
console.log(urls[i]);
fetch(urls[i], { signal: abortCont.signal }, { mode: 'cors' })
.then((res) => {
if (!res.ok) {
console.log('something went wrong with the data fetch');
}
return res.json(); // why?
})
.then((data) => {
result.push(data);
setData(result);
})
.catch((err) => {
if (err.name === 'AbortError') {
console.log('aborted');
} else {
setError(err.message);
}
});
i -= 1;
}
}, [urls]);
// console.log(data);
return { data, error };
}
export default useFetch;
--- 更新 DashBox ---
mport { Box, Grid, Container, Typography } from '@mui/material';
import ReportBox from './ReportBox';
function DashBox({ components }) {
// console.log(components);
return (
<Grid
item
columns={5}
sx={{
display: 'flex',
flexDirection: 'row',
justifyContent: 'space-evenly',
alignItems: 'stretch',
marginTop: '20px',
marginLeft: '5px'
}}
>
{components.map((component) => (
<ReportBox component={component} />
))}
</Grid>
);
}
export default DashBox;
--- 更新页面---
export default function Page() {
const optionsFilter= [
'A',
'B',
'C'
];
const [filter, setFilter] = useState('A');
const componentsPage = [
{
title: 'One',
urls: [
`http://localhost:9000/page1?filter=${filter}`,
`http://localhost:9000/page2?filter=${filter}`
]
}
];
const componentsPageGraphs = [
{
title: 'OneGraph',
urls: [
`http://localhost:9000/page1?filter=${filter}`,
`http://localhost:9000/page2?filter=${filter}`
]
}
];
return (
<Page title="Page">
<Container>
<Typography variant="h4" sx={{ mb: 5 }}>
Page
</Typography>
<Container marginBottom="10px">
<Typography marginLeft="5px" variant="h5">
Filters
</Typography>
<Grid
columns={5}
sx={{
display: 'flex',
flexDirection: 'row',
alignItems: 'stretch',
marginTop: '10px',
marginLeft: '5px',
justifyContent: 'space-evenly'
}}
>
<Grid item sx={{ pr: 5 }}>
<DropDown
options={optionsFilter}
title="Filter Type"
setData={setFilter}
data={filter}
key="one"
/>
</Grid>
</Grid>
</Container>
<br />
<Box
container
sx={{ border: 2 }}
marginLeft="20px"
pr="20px"
pb="20px"
pl="20px"
width="100%"
>
<Typography variant="h3">Page Dashboard</Typography>
<DashBox components={componentsPage} />
</Box>
<Grid container spacing={2} marginTop="20px">
{componentsPageGraphs.map((component) => (
<Grid item xs={6}>
<Typography>{component.title}</Typography>
<LineChart xtype="category" urls={component.urls} />
</Grid>
))}
</Grid>
</Container>
</Page>
);
}
---- 使用建议的 fetch 再次更新,不幸的是仍然覆盖 ---
import { useState, useEffect, useRef } from 'react';
const sameContents = (array1, array2) =>
array1.length === array2.length && array1.every((value, index) => value === array2[index]);
function useFetch(urls) {
const [data, setData] = useState(null);
const [error, setError] = useState(null);
const urlsRef = useRef(null);
if (!urlsRef.current || !sameContents(urlsRef.current, urls)) {
urlsRef.current = urls.slice();
}
useEffect(() => {
const results = [];
if (!urlsRef.current) {
return;
}
const controller = new AbortController();
const { signal } = controller;
Promise.all(
urlsRef.current.map((url) => {
fetch(url, { signal, mode: 'cors' })
.then((res) => {
if (!res.ok) {
console.log('http issue');
}
return res.json();
})
.then((data) => {
if (!signal.aborted) {
results.push(data);
setData(results);
setError(null);
}
})
.catch((error) => {
if (signal.aborted) {
return;
}
setData(null);
setError(error);
});
return () => {
controller.abort();
};
})
);
}, [urlsRef.current]);
return { data, error };
}
export default useFetch;
堆栈片段:
const {useState, useEffect} = React;
// Fake Typography component
const Typography = ({children}) => <div>{children}</div>;
// Fake Box component
const Box = ({children}) => <div>{children}</div>;
// Fake fetch hook
function useFetchHook(urls) {
const [data, setData] = useState(null);
useEffect(() => {
setTimeout(() => {
setData([
{name: "One", data: "Data for 'One'"},
{name: "Two", data: "Data for 'Two'"},
{name: "Three", data: "Data for 'Three'"},
]);
}, 500);
}, []);
return {data};
}
function ReportComponent({ data }) {
return data.map((datum) => (
<Typography>
{datum.name}: {datum.data}
</Typography>
));
}
function ReportBox({ component }) {
const { data } = useFetchHook(component.urls)
// data returns exactly as expected, an array of objects
return (
<Box>
<Typography>
{component.title}
</Typography>
{data !== null && <ReportComponent data={data} />}
</Box>
);
}
ReactDOM.render(<ReportBox component={{urls: [], title: "Example"}} />, document.getElementById("root"));
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.development.js"></script>
【问题讨论】:
-
我预计您会遇到语法错误,
{data !== null <ReportComponent data={data} />}在null之后缺少&&。此外,您使用<Box>打开但使用</Grid>关闭。请使用 minimal reproducible example 来更新您的问题,以展示问题,最好是使用 Stack Snippets([<>]工具栏按钮)的 runnable 问题。 Stack Snippets 支持 React,包括 JSX; here's how to do one. -
我更新了它 - 我将尝试制作一个 Stack Snippets,但上面的代码几乎就是我所拥有的(除非在页面中调用 ReportComponent 并呈现)
-
代码对我来说看起来不错(除了您需要在
Typography返回的Typography元素上使用key),所以我将它复制并粘贴到一个sn-p 中并写了为Typography、Box和useFetchHooik设置一些占位符/替身。它工作得很好。请更新 sn-p 以演示问题(并更新 sn-p 之外的问题中的代码以匹配,或者只是将其删除并取消选中“默认隐藏 sn-p”框)。 -
所以它会短暂显示一切正常,然后它会切换回只有一个项目。我知道数据在我将其记录到控制台时按预期存在,但它会在交换为组件中只有一项后立即出现。我认为问题出在我获取数据时,我更新了我将使用 useState 返回的值。但是,在我的 while 循环完成之前,我不会返回 { data }。我不确定为什么会发生此错误。任何建议将不胜感激!
-
现在添加断点。顺便说一句,非常感谢!
标签: javascript reactjs components