【问题标题】:Input field losing focus on each character type - react输入字段失去对每个字符类型的关注 - 反应
【发布时间】:2021-08-02 12:56:42
【问题描述】:

我正在尝试在表格的标题上添加列过滤器,但在字段上每次输入后,它就会失去焦点。

我的主要组件:在这里,我初始化了一个本地状态:searchColArrfetchData 中使用的所有其他状态都是 redux 状态,正在使用 useSelectror 进行初始化

Category.jsx

const [searchColArr, setSearchColArr] = useState({
    name: "",
});

//all these default value are either local state or redux state
function fetchData(
    newPage = page,
    newPerPage = perPage,
    newOrder = order,
    newDir = dir,
    newSearchColArr = searchColArr,
    newSearch = search
) {
    dispatch(
        listCategory(
            newPage,
            newPerPage,
            newOrder,
            newDir,
            newSearchColArr,
            newSearch
        )
    );
}

const headerRow = React.useMemo(
    () => [
        {
            header: "Name",
            name: "name",
            filter: true,
            sort: true,
        },
        {
            header: "Action",
            name: "id",
            filter: false,
            sort: false,
        },
    ],
    []
);

const TBody = () => {
        return (
            <tbody key="tbody">
                {list &&
                    list.map((row, i) => (
                        <tr key={row.id}>
                            <td>{row.name}</td>
                            <td>
                                <ActionColumn id={row.id} />
                            </td>
                        </tr>
                    ))}
            </tbody>
        );
    };

const handleColSearch = ({ currentTarget: input }) => {
    setSearchColArr({
        ...searchColArr,
        [input.name]: input.value,
    });
};
useEffect(() => {
    fetchData();
}, [searchColArr]);

return (
    <div className="row">
        <div className="col-md-12">
            {/* REDUX TABLE STARTS */}

            <ReduxTable
                key="redux-table"
                isLoading={isLoading}
                headerRow={headerRow}
                list={list}
                page={page}
                perPage={perPage}
                order={order}
                dir={dir}
                total={total}
                totalPage={totalPage}
                searchColArr={searchColArr}
                handlePageLengthChange={handlePageLengthChange}
                handlePageChange={handlePageChange}
                handleColSearch={handleColSearch}
                TBody={TBody}
            />
            {/* REDUX TABLE ENDS */}
        </div>
    </div>
);

而且,在 Redux Table 中,我正在加载另一个组件 ReduxTableHeader

ReduxTable

const ReduxTable = ({
    isLoading,
    headerRow,
    list,
    page,
    perPage,
    order,
    dir,
    total,
    totalPage,
    searchColArr,
    handlePageLengthChange,
    handlePageChange,
    handleColSearch,
    TBody,
}) => {
    return (
        <div className="card-box">

            {/* TABLE HEADER AND BODY just looping thorugh list*/}
            <table
                id="basicTable"
                className="table table-bordered action-table table-striped table-hover mb-0"
            >
                {/* ReduxTableHeader */}
                <ReduxTableHeader
                    key="redux-table-header"
                    headerRow={headerRow}
                    searchColArr={searchColArr}
                    handleColSearch={handleColSearch}
                />

                <TBody />
            </table>


        </div>
    );
};

ReduxTableHeader

    return (
        <thead key="thead">
            <tr>
                //list of header name
            </tr>
            <tr key="filter-row">
                {headerRow &&
                    headerRow.map((v, i) => (
                        <th key={v.name}>
                            {v.filter ? (
                                <input
                                    type="search"
                                    className="form-control form-control-sm d-inline-block"
                                    placeholder=""
                                    aria-controls="datatable"
                                    name={v.name}
                                    value={searchColArr[v.name] || ""}
                                    onChange={handleColSearch}
                                    autoComplete="off"
                                    key={"index" + i}
                                />
                            ) : (
                                ""
                            )}
                        </th>
                    ))}
            </tr>
        </thead>
    );

这个表头是我加载输入字段的地方,每当我在这个字母上输入时,都会失去自动焦点。我该如何解决?

【问题讨论】:

  • 每次调用 handleColSearch 后,您的组件可能会重新渲染。如果没有更多背景信息,将很难进一步诊断。
  • 你想看哪个文件,请告诉我。
  • 如果可能,请添加代码沙箱链接。

标签: reactjs redux


【解决方案1】:

您通过创建像 Tbody 这样的嵌套组件违反了 React 规则。这会在每次渲染时创建新组件(即使函数名称保持不变),并导致该组件重新挂载

在 99.999% 的情况下,您的输入失去焦点是因为它的一个父组件重新挂载,因此每次您输入内容时都会创建一个新的组件树(和新的输入元素)。您可能正在做与上面组件树中的 Tbody 相同的事情,并且每次触发 fetchData 时都会重新安装整个 Category 组件。要确认您可以注释掉这个触发fetchDatauseEffect

【讨论】:

  • 将键设置为索引也会导致重新挂载。还有那些
  • @Max 抱歉回复晚了。我明白你想说什么。但是,如果我评论了那部分,我怎么能在输入字段上调用 ​​keyup 上的数据。
  • @AayushDahal 您需要按照反应规则重写整个事情。评论该部分不是解决方案,而只是确认重新安装导致失去焦点的一种方式
  • @Max 你有资源链接吗?我可以按照哪个正确添加列过滤器?如果你有一个这样的资源链接,你能分享一个吗?
【解决方案2】:

由于input 组件失去焦点,这意味着它被重新渲染。仅当输入组件之一已更改类型或更改上层树时才会发生这种情况。在这种情况下,react 确实完成了重新渲染。

所以我猜每个渲染都定义了一个父组件 [ReduxTable, ReduxTableHeader]。就像你为 TBody 做的那样。

在这种情况下,React 认为它是一种新型组件并破坏了先前的树并执行完整的重新渲染,这会导致性能滞后,并且在您的情况下会使输入失去焦点。

关于性能,您不应该在函数内部定义组件。 它使反应变得愚蠢。

为了防止这种情况,您需要确保所有输入的父组件都在 Render 函数之外定义。在这种情况下,在函数组件之外。

请查看我的代码沙箱链接,该链接演示了 2 个案例。

  1. 当您尝试编辑第一行输入时,它不会失去焦点
  2. 当您尝试编辑 TBody 中的其他输入时,将失去焦点 也许你也有同样的问题。

https://codesandbox.io/s/react-playground-rvikz?file=/src/App.js:567-572

【讨论】:

    【解决方案3】:

    为您的输入指定一个唯一键将导致 React 重用它而不是重绘它。所以在设置视图状态后应该保持焦点。

    return (
      <thead>
        <tr>
          /list of header name
        </tr>
        <tr>
          {headerRow &&
            headerRow.map((v, i) => (
              <th key={v.name}>
                {v.filter ? (
                  <input
                     type="search"
                     className="form-control form-control-sm d-inline-block"
                     placeholder=""
                     aria-controls="datatable"
                     name={v.name}
                     value={searchColArr[v.name] || ""}
                     onChange={handleColSearch}
                     autoComplete="off"
                     key={'input' + i}
                   />
                 ) : (
                   ""
                 )}
              </th>
          ))}
        </tr>
      </thead>
    );
    

    看看this post

    【讨论】:

    • 在输入中添加键并不能解决问题,您能否再看一下代码,可能是因为重新渲染父元素?在每种类型上,它都会进行 api 调用,并且由于列表上的更新,整个表格组件可能会重新呈现。
    • 您可能必须在所有父元素上指定一个键属性
    • 我已经更新了代码并展示了我如何为每个父组件添加密钥,但仍然是同样的问题。
    • 也必须有一个密钥。同样在 category 和 ReduxTable 中
    • 好像我已经在 ReduxTable 上添加了 key,你能检查一下上面的代码,请说明你说的是哪个 tr?
    猜你喜欢
    相关资源
    最近更新 更多
    热门标签