即使设置了项目,调用时反应 useState 项目似乎是空的

Posted

技术标签:

【中文标题】即使设置了项目,调用时反应 useState 项目似乎是空的【英文标题】:React useState item seems to be empty when called even though item is set 【发布时间】:2021-03-26 12:43:15 【问题描述】:

所以我试图从 Flask API 中获取数据并将其插入到 React 表中。我可以从 API 获取数据,并将其设置为 useState 中的列表,但是,当我尝试访问该列表时,它似乎是空的。

这是我的 Flask API 路由,它工作正常并返回数据。

def get_report(productname, reportname):
    mydb = client[productname]
    mycol = mydb[reportname]
    testlist = []
    instance_list = []
    for x in mycol.find():
        print(x)
        testlist.append("instance": "x["Instance"]", "source": x["Source"], "target": x["Target"], "volume": x["Volume of Interference"])
    for instance in testlist:
        instance_list.append(instance)
    response = jsonify("data": testlist)
    response.headers.add('Access-Control-Allow-Origin', '*')
    return response

这是我的 React 组件:

import React, useEffect, useState, useMemo from 'react'
import  useTable  from 'react-table'
import './Report.css'

export default function Report(props)
    const [item, setItem] = useState([]);
    
    const getInstances = () => 
        let productname = props.match.params.name
        let reportname = props.match.params.reportname
        fetch("http://127.0.0.1:5000/app/reports/" + productname + "/" + reportname)
        .then(res => 
          return res.json();
        ).then(res => 
          setItem(res.data)
          console.log(res.data)
        ).catch(err => 
          console.log(err);
        )
    

    useEffect(() => 
        getInstances();       
    ,  []);

    const mockData = [
      
      "instance": 1, "source": "test23", "target": "test53", "volume": "test123123"
      ,
      
        "instance": 2, "source": "test24242", "target": "test22324", "volume": "test223"
      
    ]

    const COLUMNS =[
      
          Header: 'Instance no.',
          accessor: 'instance'
      ,
      
          Header: 'Source Component',
          accessor: 'source'
      ,
      
          Header: 'Target Component',
          accessor: 'target'
      ,
      
          Header: 'Interference Volume',
          accessor: 'volume'
      ,
    ];

    
    const columns = useMemo(() => COLUMNS, [])
    
    const data = useMemo(() => item, [])

    const tableInstance = useTable(
        columns,
        data
    )

    const  getTableProps, getTableBodyProps, headerGroups, rows, prepareRow = tableInstance

    return(
        <div className = "content">
          <table className="table"...getTableProps()>
            <thead>
                headerGroups.map((headerGroup) => (
                    <tr ...headerGroup.getHeaderGroupProps>
                        headerGroup.headers.map((column) =>(
                            <th ...column.getHeaderProps()>column.render('Header')</th>
                        ))                       
                    </tr>        
                ))    
            </thead>
            <tbody ...getTableBodyProps()>
                rows.map((row) => 
                        prepareRow(row)
                        return(
                            <tr...row.getRowProps()>
                            row.cells.map((cell) => (
                              <td ...cell.getCellProps()>cell.render('Cell')</td>
                            ))   
                            </tr>
                        )
                    )
            </tbody>
          </table>            
        </div>
    )

当页面重新加载并且它接收到数据时,我正在调用getInstances 函数。我已经控制台记录了getInstances()函数内的返回数据(在这种情况下为res.data),它似乎是[...,...,...,的一种形式。 ..,... 等],与mockData 相同。

mockData 在 React 表中正确呈现,但从 API 接收的数据却没有。如果我尝试控制台记录 useState 项目,它似乎是一个空列表,这可能是它无法正确渲染的原因,但我无法理解为什么会发生这种情况。我什至尝试将mockData 插入到useState 项目中,并且出现了同样的问题。是我使用的状态错误还是我的数据类型错误?

【问题讨论】:

【参考方案1】:

这是因为const data = useMemo(() =&gt; item, [])

useMemo 返回一个记忆值。它仅在依赖项之一发生更改时重新计算记忆值。如果您不提供依赖项,它只会运行一次。使用该空依赖数组,您在获取报告之前将data 设置为由useState([]) 在第一次渲染时设置的空数组。你可以运行下面的代码 sn -p 看看它是如何工作的。

无论如何,您不需要在这里使用useMemo,因为您只需通过在useEffect 挂钩中提供一个空的依赖项数组来获取页面加载报告。

如果您删除const data = useMemo(() =&gt; item, []); 并使用您的item 状态作为useTable 中的数据,您的应用应该正确呈现表格:

const tableInstance = useTable(
  columns,
  data: item,
);

function App() 
  const [items, setItems] = React.useState([]);

  const getInstances = () => 
    fetch('https://jsonplaceholder.typicode.com/albums')
      .then((res) => res.json())
      .then((data) => 
        setItems(data.slice(0, 2));
      );
  ;

  React.useEffect(() => 
    getInstances();
  , []);

  const dataWithEmptyDepArray = React.useMemo(() => items, []);
  const dataWithDepArray = React.useMemo(() => items, [items]);

  return (
    <div className="App">
      <p>
        <code>dataWithEmptyDepArray</code>
        <pre>JSON.stringify(dataWithEmptyDepArray, null, 2)</pre>
      </p>
      <p>
        <code>dataWithDepArray</code>
        <pre>JSON.stringify(dataWithDepArray, null, 2)</pre>
      </p>
      <p>
        <code>items</code>
        <pre>JSON.stringify(items, null, 2)</pre>
      </p>
    </div>
  );


ReactDOM.render(<App />, document.querySelector('#root'));
code 
  background-color: #ededed;
  padding: .25rem .5rem;


p 
  border-bottom: 1px solid #ededed;
  margin-bottom: 2rem;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>

【讨论】:

是的,就是这样,现在它可以正常工作了!不敢相信我在这个上花了几个小时。

以上是关于即使设置了项目,调用时反应 useState 项目似乎是空的的主要内容,如果未能解决你的问题,请参考以下文章

关于在反应功能组件中读取文件内容和useState钩子[重复]

在 useState 钩子中反应设置状态

反应 useState 钩子不使用 axios 调用更新

在自定义组件中调用 useState Hook 时反应本机 TextInput ReRenders

如何在本机反应中显示从可搜索下拉列表中选择的项目?

如何从另一个页面调用 useState?