在功能性 React 组件中定义处理程序的正确方法?

and*_*ero 6 javascript function nested-function reactjs react-hooks

据我所知,在 JavaScript 中定义函数有三种方式。

1. 声明

function handleEvent(e) {}
Run Code Online (Sandbox Code Playgroud)

2. 分配

var handleEvent = function(e) {}
Run Code Online (Sandbox Code Playgroud)

3. 箭头

var handleEvent = (e) => {}
Run Code Online (Sandbox Code Playgroud)

我一直在寻找有关这些选项中哪个是在功能性 React 组件中声明处理程序的首选方式的信息。我发现的所有文章都讨论了类组件、绑定等。但是随着新Hooks 的出现,在函数内部也必须有定义它们的标准。(毕竟,无论如何,功能组件一直存在。)

考虑以下组件,它声明了三个处理程序,它们是您在 React 组件中可能需要的不同行为的示例。

function NameForm(props) {
    const [inputName, setInputName] = useState("");

    useEffect(() => setInputName(props.initialValue), [props.initialValue]);

    const handleInputChange = function(event) {
        setInputName(event.target.value);
    };

    const resetForm = function() {
        setInputName(props.initialValue);
        props.onReset();
    };

    const handleFormSubmit = function(event) {
        event.preventDefault();
        props.onSubmit(inputName);
        resetForm();
    };

    /* React-Bootstrap simple form example using these handlers. */
    return (
        <Form onSubmit={handleFormSubmit}>
            <Form.Group controlId="NameForm">
                <Form.Control
                    type="text"
                    placeholder="Enter your name here"
                    value={inputName}
                    onChange={handleInputChange}
                />
                <Button type="submit">Submit</Button>
                <Button onClick={resetForm}>Reset</Button>
            </Form.Group>
        </Form>
    );
}
Run Code Online (Sandbox Code Playgroud)

所有这些处理程序都作为回调直接传递给其他组件。它们可能会在任何时候被调用,但在那个确切的时刻,我们需要访问 的当前props和任何状态,如inputName。此外,您可能已经注意到,handleFormSubmit处理程序还会调用resetForm处理程序。

从性能角度定义处理程序的推荐方法是什么?是否可以避免在每次渲染时重新定义它们?

是否useCallback还适合在这里的某个地方?

Chr*_*Ngo 5

当前的标准是将处理程序声明为不变性的常量和用于绑定目的的箭头函数。

function NameForm(props) {
    const [inputName, setInputName] = useState("");

    useEffect(() => setInputName(props.initialValue), [props.initialValue]);

    const handleInputChange = (event) => {
        setInputName(event.target.value);
    }

    const resetForm = () => {
        setInputName(props.initialValue);
        props.onReset();
    }

    const handleFormSubmit = (event) => {
        event.preventDefault();
        props.onSubmit(inputName);
        resetForm();
    }

    /* React-Bootstrap simple form example using these handlers. */
    return (
        <Form onSubmit={handleFormSubmit}>
            <Form.Group controlId="NameForm">
                <Form.Control
                    type="text"
                    placeholder="Enter your name here"
                    value={inputName}
                    onChange={handleInputChange}
                />
                <Button type="submit">Submit</Button>
                <Button onClick={resetForm}>Reset</Button>
            </Form.Group>
        </Form>
    );
}
Run Code Online (Sandbox Code Playgroud)

所有这些处理程序都作为回调直接传递给其他组件。它们可能会在任何时候被调用,但在那个确切的时刻,我们需要访问 props 的当前值和任何状态,如 inputName

按照目前的建造,我们满足您的描述要求。由于propsstate被定义为组件可以访问的更高级别的数据,因此所有事件处理程序都可以访问它们。当在另一个组件中用作回调时,它们将保持绑定到定义它们的初始组件。

这意味着如果您有这样的事件处理程序:

const handleInputChange = (e) => {
    setValue(e.target.value)
}
Run Code Online (Sandbox Code Playgroud)

你把它传递给一个 ChildComponent 像这样:

<Child handleInputChange={handleInputChange}/>
Run Code Online (Sandbox Code Playgroud)

Child 像这样使用 prop/event-handler:

<input onChange={props.handleInputChange}/>
Run Code Online (Sandbox Code Playgroud)

您将从eventChild 输入中获取 ,但您将更新state定义事件处理程序的原始组件 Parent 的 。

  • 实际上,有`useCallback`:https://reactjs.org/docs/hooks-reference.html#usecallback (4认同)
  • 我相信这个答案可以通过添加“useCallback”来改进。它可以防止在每个渲染上重新定义处理程序,除非某些道具发生变化。 (2认同)

And*_*uca 5

“声明”、“赋值”和“箭头”方法之间实际上没有区别。唯一重要的是,您并不总是在每个渲染上创建处理函数的新实例。为此,请使用useCallback钩子来记住函数引用:

const handleInputChange = useCallback((event) => {
  setInputName(event.target.value);
}, []); // `setInputName` is guaranteed to be unique, from the React Hooks docs, so no need to pass it as a dependency

const resetForm = useCallback(() => {
  setInputName(props.initialValue);
  props.onReset();
}, [props.onReset, props.initialValue]; // these come from props, so we don't know if they're unique => need to be passed as dependencies

const handleFormSubmit = useCallback((event) => {
    event.preventDefault();
    props.onSubmit(inputName);
    resetForm();
}, [props.onSubmit, resetForm, inputName]); // `resetForm` and `inputName`, although defined locally, will change between renders, so we also need to pass them as dependencies
Run Code Online (Sandbox Code Playgroud)

useCallback文档: https: //reactjs.org/docs/hooks-reference.html#usecallback

  • 是的,存在技术差异,例如吊装。但就你的问题而言,这并不重要。重要的是您不要在每次新渲染时重新声明它们。而 `useCallback` 正是这样做的。 (2认同)