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

时间:2019-08-03 09:22:22

标签: javascript reactjs function react-hooks nested-function

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

1。声明

function handleEvent(e) {}

2。分配

var handleEvent = function(e) {}

3。箭头

var handleEvent = (e) => {}

我已经花了数小时试图寻找信息,以了解在功能性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>
    );
}

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

从性能的角度来看,定义处理程序的推荐方法是什么?是否可以避免在每个渲染器上都重新定义它们?

useCallback也适合放在这里吗?

3 个答案:

答案 0 :(得分:2)

当前的标准是将处理程序声明为不可变的常量,并声明为绑定目的的箭头函数。

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>
    );
}
  

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

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

这意味着您是否具有这样的事件处理程序:

const handleInputChange = (e) => {
    setValue(e.target.value)
}

然后将其传递给子组件,如下所示:

<Child handleInputChange={handleInputChange}/>

孩子使用prop / event-handler像这样:

<input onChange={props.handleInputChange}/>

您将从子项输入中获取event,但是将更新父级的state,父项是定义事件处理程序的原始组件。

答案 1 :(得分:2)

“声明”,“分配”和“箭头”方法之间几乎没有区别。唯一重要的是,您不必总是在每个渲染器上创建处理程序函数的新实例。为此,请使用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

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

答案 2 :(得分:0)

在功能组件中,我们不需要访问this(甚至更多-在这种情况下,大多数短毛猫都会向您发出警告-并且是有原因的!)。因此,无论我们使用箭头表达式还是声明函数都没有关系。

但是性能很重要。您从列表中选择的任何选项都会在每个渲染器上重新创建。声明函数本身并不是什么大问题,但是:

  1. 传递给子组件可能会导致不必要地重新渲染PureComponent / React.memo包装的组件。
  2. 如果稍后将useMemo /其他useCallback / useEffect的处理程序添加到依赖项列表中,可能会导致多余的运行。

所以要么在组件之外声明处理程序(一旦它完全不依赖内部状态),要么使用useCallback。注意,它需要您明确列出所有依赖项-不要忽略它。否则结果处理程序可能会对过时的数据进行操作。