[英]Material-UI - fetching data display in DataTable => “React.useState” cannot be called inside a callback
我復制了 ReactTables.js 並且我一直在修改它以顯示我自己的數據。 一開始,我把我的數據放在/variables/general.js 文件中,我可以在表格中顯示它。
下一步是從 REST 服務中獲取數據。 我已經編寫了函數來做到這一點,並首先在 Node 中測試它們,甚至是 fetch 部分,現在我試圖將它們折疊到 React 代碼中。 我知道數據格式正確,適用於 dataTable 結構。
當我從靜態數據切換到獲取數據並將“React.useState”放在 .then 子句下時,我開始收到錯誤:無法在回調中調用 React Hook“React.useState”。 React Hooks 必須在 React 函數組件或自定義 React Hook 函數 react-hooks/rules-of-hooks 中調用。 我嘗試將我的代碼放在 React.use 下,但看起來它需要 parms,而不是那里的代碼。
這是我的代碼,不包括動作和樣式。 同樣,它基本上是他們的開箱即用代碼,只是嘗試插入獲取以獲取動態數據。 當我調用我的 getDBLanguagesAndConvertToDataTable 時,我需要使用 .then。
我做了一些關於鈎子的基本閱讀,但迷路了。 還有其他地方我應該從 REST 服務中檢索數據嗎?
import React from "react";
// @material-ui/core components
import { makeStyles } from "@material-ui/core/styles";
// @material-ui/icons
import Assignment from "@material-ui/icons/Assignment";
import Dvr from "@material-ui/icons/Dvr";
import Favorite from "@material-ui/icons/Favorite";
import Close from "@material-ui/icons/Close";
// core components
import GridContainer from "components/Grid/GridContainer.js";
import GridItem from "components/Grid/GridItem.js";
import Button from "components/CustomButtons/Button.js";
import Card from "components/Card/Card.js";
import CardBody from "components/Card/CardBody.js";
import CardIcon from "components/Card/CardIcon.js";
import CardHeader from "components/Card/CardHeader.js";
import ReactTable from "components/ReactTable/ReactTable.js";
import { dataTable } from "variables/general.js";
import { cardTitle } from "assets/jss/material-dashboard-pro-react.js";
const styles = {
cardIconTitle: {
...cardTitle,
marginTop: "15px",
marginBottom: "0px"
}
};
const useStyles = makeStyles(styles);
function convertMongoLanguagesToDataTable(argDbGetResults) {
//console.log("function convertMongoLanguagesToDataTable")
//console.log("Input:" + JSON.stringify(argDbGetResults))
const dataTable = {
headerRow: ["SourceLanguage", "SourcePhrase", "TargetLanguage", "TargetPhrase", "ID"],
footerRow: ["SourceLanguage", "SourcePhrase", "TargetLanguage", "TargetPhrase", "ID"],
dataRows: []
};
var temporaryMax = argDbGetResults.length
temporaryMax = 3 // get a smaller sample for easier debugging/testing
for (var j = 0; j < argDbGetResults.length; j++) {
var row = argDbGetResults[j]
var strRow = JSON.stringify(row);
//console.log(j, strRow)
var newArray = [row.masterLanguage, row.masterPhrase, row.localizedLanguage, row.localizedPhrase, row._id]
dataTable.dataRows.push(newArray)
}
//console.log("return from function convertMongoLanguagesToDataTable")
//console.log("dataTable:" + JSON.stringify(dataTable))
return dataTable
}
function getDBLanguagesAndConvertToDataTable(fromLanguage, toLanguage) {
// pass the from/to Language on the URL
var url = 'http://localhost:3001/api/gettranslations/' + fromLanguage + "/" + toLanguage
var fetchOptions = {
method: 'GET',
headers: {
'Accept': 'application/json',
}
}
return fetch(url, fetchOptions)
.then(function(data) {
// do something with the data
data.json()
.then (function(fetchResult) {
//console.log("data.json() from Fetch From gettranslation REST service:")
//console.log(JSON.stringify(fetchResult))
var tmpDataTable = convertMongoLanguagesToDataTable(fetchResult)
console.log("return from function convertMongoLanguagesToDataTable")
console.log("PostFetch dataTable:" + JSON.stringify(tmpDataTable))
return tmpDataTable
})
})
.catch(function(err){
console.log("Fetch Error url:" + url)
console.log("Fetch Error:" + err)
throw new Error(err)
})
}
export default function ReactTables() {
var fromLanguage = 'en-US'
var toLanguage = 'es-MX'
getDBLanguagesAndConvertToDataTable(fromLanguage, toLanguage)
.then(function(dataTable) {
console.log("tmpDataTable type=" + typeof dataTable)
var strDataTable = JSON.stringify(dataTable, null, 3);
console.log("Resulting DataTable=")
console.log(strDataTable)
if (dataTable === null || dataTable === undefined) {
console.log('dataTable is null or undefined')
}
if (dataTable.dataRows === null || dataTable.dataRows === undefined) {
console.log('dataTable.dataRows is null or undefined')
}
console.log("Number of dataRows=" + dataTable.dataRows.length)
const [data, setData] = React.useState(
dataTable.dataRows.map((prop, key) => {
return {
ID: key,
SourceLanguage: prop[0],
SourcePhrase: prop[1],
TargetLanguage: prop[2],
TargetPhrase: prop[3],
actions: (
// code omitted
)
};
})
);
const classes = useStyles();
return (
// code omitted
);
}) // end of .then for getting dataTable
}
編輯 - 第 2 部分
嘗試馬科斯回答后的新代碼。 我不得不注釋掉地圖末尾的最后一個“)”。 它編譯,但現在給出錯誤:
Error: Objects are not valid as a React child (found: object with keys {ID, SourceLanguage, SourcePhrase, TargetLanguage, TargetPhrase, actions}). If you meant to render a collection of children, use an array instead.
in ReactTables (created by Context.Consumer)
代碼
export default function ReactTables() {
const [data, setData] = React.useState()
React.useEffect(() => {
var fromLanguage = 'en-US'
var toLanguage = 'es-MX'
getDBLanguagesAndConvertToDataTable(fromLanguage, toLanguage)
.then(function(dataTable) {
console.log("tmpDataTable type=" + typeof dataTable)
var strDataTable = JSON.stringify(dataTable, null, 3)
console.log("dataTable=")
console.log(dataTable)
if (dataTable === null || dataTable === undefined) {
console.log('dataTable is null or undefined')
}
if (dataTable.dataRows === null || dataTable.dataRows === undefined) {
console.log('dataTable.dataRows is null or undefined')
}
console.log("Number of dataRows=" + dataTable.dataRows.length)
setData(dataTable)
});
}, [])
return dataTable.dataRows.map((prop, key) => {
return {
ID: key,
SourceLanguage: prop[0],
SourcePhrase: prop[1],
TargetLanguage: prop[2],
TargetPhrase: prop[3],
actions: (
// code omitted
)
};
})
//); -- had to comment this out!
const classes = useStyles();
return (
<GridContainer>
// Code omitted
</GridContainer>
);
}
鈎子只能在渲染函數上調用,如果使用,必須始終調用,並且始終以相同的順序調用。
您正在Promise
的回調中使用useState
。 取而代之的是,您必須在組件上使用它並使用useEffect
來調用您的數據獲取邏輯並根據結果設置狀態。
如果您需要操作數據以顯示它,您可以使用useMemo
從原始數據中獲取處理后的數據,並僅在數據更改時執行此操作。 一定要從狀態中的data
集中獲取數據。
最后,因為useEffect
將在初始渲染后運行,所以您的數據不一定可用,因為正在檢索數據或出現錯誤。 您可以使用條件返回來處理此問題,只需確保將所有鈎子放在條件返回之前,因為如前所述,您不能修改對渲染之間的任何鈎子的任何調用。
export default function ReactTables() {
const [data, setData] = React.useState()
React.useEffect(() => {
getDBLanguagesAndConvertToDataTable()
.then(result => {
setData(result)
});
}, [])
const processedData = React.useMemo(() => data && data.dataRows.map((prop, key) => {
return {
ID: key,
SourceLanguage: prop[0],
SourcePhrase: prop[1],
TargetLanguage: prop[2],
TargetPhrase: prop[3],
actions: (
// code omitted
)
};
}), [data])
const classes = useStyles()
if (!processedData) {
return null // Use a loading component if you prefer
}
return (
<GridContainer>
// Code omitted
</GridContainer>
);
}
Ciao, React.useState
用於定義一個狀態變量,必須在組件體中使用。 就像是:
export default function ReactTables(){
const [data, setData] = React.useState([]) // [] this is the initial value for data
...
}
然后,在.then
回調中,您可以通過調用setData(/*data from fetch*/)
來設置此狀態。
第2部分
假設dataTable.dataRows
是一個數組,我認為您的問題出在map
函數中,特別是在actions
。 您不能返回類似actions: (...)
因為 JSON 對象中不允許使用圓括號。 如果actions
是一個數組,則將actions
actions: (...)
替換為actions: [...]
。 如果actions
是一個對象,則將actions
actions: (...)
替換為actions: {...}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.