将类组件转换为功能组件 TypeError: users.filter is not a function

Posted

技术标签:

【中文标题】将类组件转换为功能组件 TypeError: users.filter is not a function【英文标题】:Converting class component to functional component TypeError: users.filter is not a function 【发布时间】:2021-09-11 05:31:53 【问题描述】:

创建一个员工目录,我正在尝试将类组件转换为功能组件。导航、搜索和表格将呈现,但对 api 的调用不起作用。得到一个 TypeError: users.filter is not a function 这是工作的类组件和正在进行的功能组件。我不知道有什么不同。

import React,  Component  from "react";
import DataTable from "./DataTable";
import Nav from "./Nav";
import API from "../utils/API";
import "../styles/DataArea.css";

export default class DataArea extends Component 
  state = 
    users: [],
    order: "descend",
    filteredUsers: []
  

  headings = [
     name: "Image", width: "10%" ,
     name: "Name", width: "10%" ,
     name: "Phone", width: "20%" ,
     name: "Email", width: "20%" ,
     name: "DOB", width: "10%" 
  ]

  handleSort = heading => 
    if (this.state.order === "descend") 
      this.setState(
        order: "ascend"
      )
     else 
      this.setState(
        order: "descend"
      )
    

    const compareFnc = (a, b) => 
      if (this.state.order === "ascend") 
        // account for missing values
        if (a[heading] === undefined) 
          return 1;
         else if (b[heading] === undefined) 
          return -1;
        
        // numerically
        else if (heading === "name") 
          return a[heading].first.localeCompare(b[heading].first);
         else 
          return a[heading] - b[heading];
        
       else 
        // account for missing values
        if (a[heading] === undefined) 
          return 1;
         else if (b[heading] === undefined) 
          return -1;
        
        // numerically
        else if (heading === "name") 
          return b[heading].first.localeCompare(a[heading].first);
         else 
          return b[heading] - a[heading];
        
      

    
    const sortedUsers = this.state.filteredUsers.sort(compareFnc);
    this.setState( filteredUsers: sortedUsers );
  

  handleSearchChange = event => 
    console.log(event.target.value);
    const filter = event.target.value;
    const filteredList = this.state.users.filter(item => 
      // merge data together, then see if user input is anywhere inside
      let values = Object.values(item)
        .join("")
        .toLowerCase();
      return values.indexOf(filter.toLowerCase()) !== -1;
    );
    this.setState( filteredUsers: filteredList );
  

  componentDidMount() 
    API.getUsers().then(results => 
      this.setState(
        users: results.data.results,
        filteredUsers: results.data.results
      );
    );
  

  render() 
    return (
      <>
        <Nav handleSearchChange=this.handleSearchChange />
        <div className="data-area">
          <DataTable
            headings=this.headings
            users=this.state.filteredUsers
            handleSort=this.handleSort
          />
        </div>
      </>
    );
  

import React,  useState, useEffect  from "react";
import DataTable from "./DataTable";
import Nav from "./Nav";
import API from "../utils/API";
import "../styles/DataArea.css";

const DataArea = () => 

  const [users, setUsers] = useState([]);
  const [order, setOrder] = useState("descend");
  const [filteredUsers, setFilteredUsers] = useState([]);


  const headings = [
     name: "Image", width: "10%" ,
     name: "Name", width: "10%" ,
     name: "Phone", width: "20%" ,
     name: "Email", width: "20%" ,
     name: "DOB", width: "10%" ,
  ];

  const handleSort = (heading) => 

    if (order === "descend") 
      setOrder((order = "ascend"));
     else 
      setOrder((order = "descend"));
    

    const compareFnc = (a, b) => 
      if (order === "ascend") 
        // account for missing values
        if (a[heading] === undefined) 
          return 1;
         else if (b[heading] === undefined) 
          return -1;
        
        // numerically
        else if (heading === "name") 
          return a[heading].first.localeCompare(b[heading].first);
         else 
          return a[heading] - b[heading];
        
       else 
        // account for missing values
        if (a[heading] === undefined) 
          return 1;
         else if (b[heading] === undefined) 
          return -1;
        
        // numerically
        else if (heading === "name") 
          return b[heading].first.localeCompare(a[heading].first);
         else 
          return b[heading] - a[heading];
        
      
    ;

    const sortedUsers = filteredUsers.sort(compareFnc);
    setFilteredUsers( filteredUsers: sortedUsers );
  ;

  let handleSearchChange = (event) => 
    console.log(event.target.value);
    const filtered = event.target.value;
    const filteredList = users.filter((item) => 
      // merge data together, then see if user input is anywhere inside
      let values = Object.values(item).join("").toLowerCase();
      return values.indexOf(filtered.toLowerCase()) !== -1;
    );
    setFilteredUsers((filteredUsers = filteredList));
  ;

  useEffect(() => 
    API.getUsers().then((results) => 
      setUsers(
        users: results.data.results,
        filteredUsers: results.data.results,
      );
    );

  , []);
  return (
    <>
      <Nav handleSearchChange=handleSearchChange />
      <div className="data-area">
        <DataTable
          headings=headings
          users=filteredUsers
          handleSort=handleSort
        />
      </div>
    </>
  );
;

export default DataArea;

【问题讨论】:

我的错。感谢您修复 @DrewReese! 【参考方案1】:

问题在于您的useEffect 钩子,您将usersfilteredUsers 都硬塞到users 状态中。

useEffect(() => 
  API.getUsers().then((results) => 
    setUsers(
      users: results.data.results,
      filteredUsers: results.data.results,
    );
  );
, []);

应该是

useEffect(() => 
  API.getUsers().then((results) => 
    setUsers(results.data.results);
    setFilteredUsers(results.data.results),
  );
, []);

您希望同时填充 users 状态和单独的 filteredUsers 状态。

设置排序顺序的问题,您正在改变order 状态:

if (order === "descend") 
  setOrder((order = "ascend")); // <-- mutates
 else 
  setOrder((order = "descend")); // <-- mutates

您可以简单地在两者之间切换:

setOrder(order => order === 'ascend' ? 'descend' : 'ascend');

另一个问题是在您的 handleSort 函数的末尾:

const sortedUsers = filteredUsers.sort(compareFnc);
setFilteredUsers( filteredUsers: sortedUsers );

这将嵌套filteredUsers数组,并就地改变数组,它可能应该使用功能状态更新从先前的状态更新,使用array.slice进行复制,然后调用sort。

setFilteredUsers(filteredUsers => filteredUsers.slice().sort(compareFnc));

【讨论】:

这是可行的,但是当页面开始呈现时,我得到一个失败的编译并且这个错误:` 期望一个赋值或函数调用,而是看到一个表达式 no-unused-expressions` 知道了,我用逗号代替了分号。非常感谢朋友! @KevinMillhouse 啊,太棒了!如果此答案已充分解决您的问题/问题,那么我邀请您接受它(***.com/help/someone-answers)。不要忘记为您在 SO 上找到的有用和/或有用的问题、答案和 cmets 投票。干杯,祝你好运。 太棒了!回答采纳!也感谢您添加的反馈!!我从来没有想过使用三元来切换。非常感谢并再次感谢您的帮助! @KevinMillhouse 如果您将order 转换/重命名为orderAscend 并使其成为布尔值,那么切换它会变得更加简单,setOrderAscend(order =&gt; !order) 然后只需检查if (orderAscend) .....

以上是关于将类组件转换为功能组件 TypeError: users.filter is not a function的主要内容,如果未能解决你的问题,请参考以下文章

如何将类组件转换为功能组件?

将类组件转换为功能组件

将类组件转换为功能组件后的问题[重复]

React将类组件转换为功能组件不起作用

使用钩子将类组件转换为函数式

将类重构为 React 中的功能组件