首页 > 解决方案 > 无法使用文本输入值更新 React 状态

问题描述

我想要做的是我想从 API 获取员工列表,将它们保存在状态中,并按员工姓名进行“实时”搜索。

我挣扎的地方是我无法用过滤数组更新我的状态。当我开始在搜索字段中输入时,员工会过滤,但是一旦我删除了一些字母,什么都没有改变。

如果我 .map() 不是状态,而是包含过滤数组的变量,那么一切正常。这在某种程度上与状态和状态更新有关。

这是我的代码:

import "./App.css";
import React, { useState, useEffect } from "react";
import styled from "styled-components";

const Container = styled.div`
  width: 1280px;
  max-width: 100%;
  margin: 0 auto;
  th {
    text-align: left;
    padding: 10px;
    background: #f5f5f5;
    cursor: pointer;
    :hover {
      background: #ddd;
    }
  }
  td {
    border-bottom: 1px solid #f5f5f5;
    padding: 5px;
  }
`;
const TopHeader = styled.div`
  display: flex;
  justify-content: space-between;
  padding: 20px;
  input {
    width: 400px;
    padding: 10px;
  }
`;

function App() {
  const [employees, updateEmployees] = useState([]);

  if (employees == 0) {
    document.title = "Loading...";
  }

  useEffect(() => {
    fetch("http://dummy.restapiexample.com/api/v1/employees")
      .then(res => res.json())
      .then(result => {
        updateEmployees(result.data);
        document.title = `Total: ${result.data.length} `;
      });
  }, []);

  const [searchValue, updateSearch] = useState("");

  const filteredEmpl = employees.filter(empl => {
    return empl.employee_name.toLowerCase().includes(searchValue.toLowerCase());
  });

  const handleSearch = e => {
    updateSearch(e.target.value);
    updateEmployees(filteredEmpl);
  };

  return (
    <Container>
      <TopHeader>
        <div>
          Total employees: <strong>{employees.length}</strong> Filtered
          employees: <strong>{filteredEmpl.length}</strong>
        </div>
        <div>
          <input
            type="text"
            onChange={handleSearch}
            value={searchValue}
            placeholder="search"
          />
        </div>
      </TopHeader>

      <table style={{ width: "100%" }}>
        <thead>
          <tr>
            <th>id</th>
            <th>Employee name</th>
            <th>Employee salary</th>
            <th>Employee age</th>
          </tr>
        </thead>
        <tbody>
          {employees.map(employee => (
            <tr key={employee.id}>
              <td>{employee.id}</td>
              <td>{employee.employee_name}</td>
              <td>{employee.employee_salary}</td>
              <td>{employee.employee_age}</td>
            </tr>
          ))}
        </tbody>
      </table>
    </Container>
  );
}

export default App;

任何想法缺少什么?

标签: javascriptreactjsreact-hooksstate

解决方案


我通过更改几个变量名称并添加了过滤器功能对您的代码进行了一些调整。我希望这有帮助。如果您在此问题上需要任何进一步的帮助,请告诉我。干杯!

import React, { useState, useEffect } from "react";
import styled from "styled-components";

import "./App.css";

const Container = styled.div`
  width: 1280px;
  max-width: 100%;
  margin: 0 auto;
  th {
    text-align: left;
    padding: 10px;
    background: #f5f5f5;
    cursor: pointer;
    :hover {
      background: #ddd;
    }
  }
  td {
    border-bottom: 1px solid #f5f5f5;
    padding: 5px;
  }
`;

const TopHeader = styled.div`
  display: flex;
  justify-content: space-between;
  padding: 20px;
  input {
    width: 400px;
    padding: 10px;
  }
`;

const Loading = styled.div`
  display: flex;
  text-align: 'center';
  padding: 20px;
  font-size: 2em;
  font-weight: 300;
`;

const App = () => {
    const [employees, setEmployees] = useState([]); // Change variable name from updateEmployees to setEmployees
    const [searchValue, setSearchValue] = useState(""); // changed variable name from updateSearch to setSearchValue
    const [employeesTotal, setEmployeesTotal] = useState(0); // Add a new state to handle intial employees total

    // Renamed employees variable to employeesTotal
    if (employeesTotal) {
        document.title = "Loading...";
    }

    useEffect(() => {
        fetch("http://dummy.restapiexample.com/api/v1/employees")
            .then(res => res.json())
            .then(result => {
                setEmployees(result.data);
                setEmployeesLength(result.data.length);
                document.title = `Total: ${result.data.length} `; // Why though?
            });
    }, []);

    const handleSearch = e => {
        setSearchValue(e.target.value);
    };

    const filterDocument = doc => {
        const employeeName = doc.employee_name.toLowerCase() || '';
        return employeeName.includes(searchValue.toLowerCase());
    };

    // Check if employees array contains data, if it does, display content, otherwise show loading
    return (
            employeesTotal ? (
                <Container>
                    <TopHeader>
                        <div>
                            Total employees: <strong>{employeesTotal}</strong> Filtered employees: <strong>{employees.length}</strong>
                        </div>
                        <div>
                            <input
                                type="text"
                                onChange={handleSearch}
                                value={searchValue}
                                placeholder="search"
                            />
                        </div>
                    </TopHeader>

                    <table style={{ width: "100%" }}>
                        <thead>
                            <tr>
                                <th>id</th>
                                <th>Employee name</th>
                                <th>Employee salary</th>
                                <th>Employee age</th>
                            </tr>
                        </thead>
                        <tbody>
                            {/** Add filterDocument to filter function on employee array before calling its map funtion */}
                            {employees.filter(filterDocument).map(employee => (
                                <tr key={employee.id}>
                                    <td>{employee.id}</td>
                                    <td>{employee.employee_name}</td>
                                    <td>{employee.employee_salary}</td>
                                    <td>{employee.employee_age}</td>
                                </tr>
                            ))}
                        </tbody>
                    </table>
                </Container>
            ) : (
                    <Loading>Loading...</Loading>
                )
    );
}

export default App;

推荐阅读