我的目的是创建一个自定义输入元素,避免在输入值更改时重新渲染,但同时如果输入更改则通知父级。
输入组件:
import { useRef, useEffect, ChangeEvent } from "react";
type props = {
changeFunction?: (e: ChangeEvent<HTMLInputElement>) => void;
};
function TestInput({ changeFunction }: props) {
let inputRef = useRef<HTMLInputElement>(null);
useEffect(() => {
console.log("Input render");
});
function change(e: ChangeEvent<HTMLInputElement>) {
console.log("Input change", e.target.value);
if (inputRef.current) inputRef.current.value = e.target.value;
if (changeFunction) changeFunction(e);
}
return (
<input
ref={inputRef}
type="search"
id="test"
name="test"
autoComplete="off"
onChange={change}
/>
);
}
export default TestInput;
父组件:
import { useCallback, useState, ChangeEvent } from "react";
import TestInput from "./Test";
function TestParent() {
let [value, setValue] = useState("");
let change = useCallback(
(e: ChangeEvent<HTMLInputElement>) => setValue(e.target.value),
[]
);
return (
<div>
<p>Value: {value}</p>
<TestInput changeFunction={change} />
</div>
);
}
export default TestParent;
尽管使用了
useCallback
,输入组件每次都会重新渲染。如果我们排除 changeFunction
属性,这种情况就不会发生。有什么解决办法吗?
这是一个堆栈片段,没有显示问题的 TypeScript 部分。
const { useState, useEffect, useCallback, useRef } = React;
function TestInput({ changeFunction }) {
let inputRef = useRef(null);
useEffect(() => {
console.log("Input render");
});
function change(e) {
console.log("Input change", e.target.value);
if (inputRef.current) inputRef.current.value = e.target.value;
if (changeFunction) changeFunction(e);
}
return (
<input
ref={inputRef}
type="search"
id="test"
name="test"
autoComplete="off"
onChange={change}
/>
);
}
function TestParent() {
let [value, setValue] = useState("");
let change = useCallback(
(e) => setValue(e.target.value),
[]
);
return (
<div>
<p>Value: {value}</p>
<TestInput changeFunction={change} />
</div>
);
}
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<TestParent />);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.development.js"></script>
您不需要避免子组件的重新渲染。这就是 React 计算出对 dom 进行必要更改的方式。因此,除非您的用例特别要求子组件不重新渲染,否则您应该避免此类性能优化。
您可以记忆子组件
import { memo } from 'react';
// ...
export default memo(TestInput);