【问题标题】:Bind input field to grid component将输入字段绑定到网格组件
【发布时间】:2021-03-12 18:36:38
【问题描述】:

如何将SearchFilter 的值与FilterGrid 同步,以便过滤数据(参见下面的代码)?我在输入时遇到了字段清除值的问题。我使用状态挂钩的方式一定有问题。

问题可能归因于我在位于SearchFilterhandleOnChange 函数内部调用onChange 的方式。我将onChange“listener”作为属性传递给过滤器,以便我可以访问过滤器之外的值。

不确定这是否不是正确的方法,因为将值直接绑定到网格中的搜索字段给了我这个警告:

“警告:组件正在将受控输入更改为不受控。这可能是由于值从已定义更改为未定义引起的,这不应该发生。决定使用受控输入元素还是不受控输入元素组件的生命周期。”


这是一个实时沙盒的链接:

https://codesandbox.io/s/react-material-ui-search-d4073?file=/src/App.jsx

App.jsx

import React, { useEffect, useState } from "react";
import FilterGrid from "./components/FilterGrid";
import jsonData from "./data/data.json";

const fetchData = () => Promise.resolve(jsonData);

const App = () => {
  const [data, setData] = useState([]);

  useEffect(() => {
    fetchData().then((json) => setData(json));
  }, []);

  const columns = [
    { key: "nameField", field: "name", title: "Name" },
    { key: "ageField", field: "age", title: "Age" }
  ];

  return <FilterGrid data={data} columns={columns} />;
};

export default App;

FilterGrid.jsx

import React, { useState } from "react";
import SearchFilter from "./SearchFilter";
import MaterialTable from "material-table";

const FilterGrid = (props) => {
  const { data, columns } = props;
  const [filterValue, setFilterValue] = useState("");

  const handleChange = (value) => {
    setFilterValue(value);
    console.log("Value changed...");
  };

  const applyFilter = (records) =>
    records.filter((record) =>
      Object.values(record).some((value) => `${value}`.includes(filterValue))
    );

  const toolbar = () => (
    <div
      style={{
        display: "flex",
        flex: 1,
        flexDirection: "row",
        justifyContent: "flex-end"
      }}
    >
      <SearchFilter
        listeners={{
          onChange: handleChange
        }}
      />
    </div>
  );

  console.log("Changed filter:", filterValue);

  return (
    <div>
      <MaterialTable
        data={applyFilter(data)}
        columns={columns}
        components={{
          Toolbar: toolbar
        }}
        options={{
          search: false
        }}
      />
    </div>
  );
};

export default FilterGrid;

SearchFilter.jsx

import { FormControl, Input } from "@material-ui/core";
import React, { useState } from "react";
import PropTypes from "prop-types";

const SearchFilter = (props) => {
  const {
    listeners: { onChange }
  } = props;

  const [internalValue, setInternalValue] = useState("");

  const handleOnChange = (e) => {
    setInternalValue(e.target.value);
    onChange(internalValue);
  };

  return (
    <FormControl>
      <Input
        type="search"
        placeholder="Search..."
        onChange={(e) => handleOnChange(e)}
        value={internalValue}
      />
    </FormControl>
  );
};

export default SearchFilter;

data.json

[
  { "name": "Bill", "age": 21 },
  { "name": "Bob", "age": 31 },
  { "name": "Brad", "age": 41 }
]

package.json

{
  "dependencies": {
    "@material-ui/core": "4.11.1",
    "material-table": "1.69.2",
    "prop-types": "15.7.2",
    "react": "17.0.0",
    "react-dom": "17.0.0"
  }
}

index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>React Material UI Search</title>
    <link
      rel="stylesheet"
      href="https://fonts.googleapis.com/icon?family=Material+Icons"
    />
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>

【问题讨论】:

    标签: javascript reactjs data-binding


    【解决方案1】:

    当你这样做时,问题是 setState 的异步性质:

      const handleOnChange = (e) => {
        setInternalValue(e.target.value);
        onChange(internalValue);
      };
    

    在执行onChange 后,internalValue 仍然为空(它不会等待 setInternalValue)来更新状态。

    还有其他需要考虑的事情。您正在复制状态,这不是一个好习惯。您最好将过滤器状态保持在FilterGrid 并作为道具传递。

    我注意到的另一件事是输入中的每种类型都会模糊输入字段。如果您在外部声明 ToolTip 并且不将其作为组件参数传递给 FilterGrid

    ,则可以避免这种情况

    过滤网格

    import React, { useState } from "react";
    import SearchFilter from "./SearchFilter";
    import MaterialTable from "material-table";
    
    const Toolbar = ({ filterValue, setFilterValue }) => (
      <div
        style={{
          display: "flex",
          flex: 1,
          flexDirection: "row",
          justifyContent: "flex-end"
        }}
      >
        <SearchFilter filterValue={filterValue} setFilter={setFilterValue} />
      </div>
    );
    
    const FilterGrid = (props) => {
      const { data, columns } = props;
      const [filterValue, setFilterValue] = useState("");
    
      const applyFilter = (records) =>
        records.filter((record) =>
          Object.values(record).some((value) => `${value}`.includes(filterValue))
        );
    
      console.log("Changed filter:", filterValue);
    
      return (
        <div>
          <Toolbar filterValue={filterValue} setFilterValue={setFilterValue} />
          <MaterialTable
            data={applyFilter(data)}
            columns={columns}
            options={{
              search: false
            }}
          />
        </div>
      );
    };
    
    export default FilterGrid;
    

    搜索过滤器

    import { FormControl, Input } from "@material-ui/core";
    import React from "react";
    import PropTypes from "prop-types";
    
    const SearchFilter = (props) => {
      const { filterValue, setFilter } = props;
    
      const handleOnChange = (e) => {
        setFilter(e.target.value);
      };
    
      return (
        <FormControl>
          <Input
            type="search"
            placeholder="Search..."
            onChange={handleOnChange}
            value={filterValue}
          />
        </FormControl>
      );
    };
    
    SearchFilter.propTypes = {
      filterValue: PropTypes.string.isRequired,
      setFilter: PropTypes.func.isRequired
    };
    
    export default SearchFilter;
    

    【讨论】:

    • 所以没有办法通过components.Toolbar = () =&gt; (&lt;Toolbar ... /&gt;)从网格中设置工具栏?
    • 我不知道。您想要的方法会强制在 ToolBar 上重新渲染,从而导致每个用户类型的 SeachField 模糊。
    猜你喜欢
    • 1970-01-01
    • 2023-03-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-18
    • 2016-12-10
    相关资源
    最近更新 更多