簡體   English   中英

Material-UI - 在 DataTable 中獲取數據顯示 => “React.useState” 不能在回調中調用

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM