最近在使用 React 进行开发时,发现了一个容易被忽视的细节,特此分享。

在使用函数组件时,我们通常会定义一些 props,但要注意在传参的时候存在一些潜在的问题。

例子

让我们来看一个函数组件:

const Search = (query, engine) => {
    ...
}
export default OneSearch;

在引用这个组件时,可能会这样写:

<Search query={query} engine={engine} />

表面上看起来一切正常,但如果仔细观察函数组件的定义,会发现一个小小的细节,就在传参的地方:(query, engine)

实际上,我们希望应该是这样:({ query, engine })

原因

为什么呢?因为在 React 中,组件的参数是作为一个 JavaScript 对象传递的。在定义函数组件时,我们可以将参数写作 (props) 或者其他任何名字,比如 (foo)。而在引用组件时,JSX 会将传递的参数名和值打包成一个 JavaScript 对象,作为实参传递给组件。props 只是一个约定俗称的名字,你可以通过这个名字来访问传递过来的参数。

另一种写法是 ({ query, engine }),此时形参变成了一个对象,而 JavaScript 语法允许你通过这种形式直接访问对象中的属性。

但是,如果你采用 (query, engine) 这种写法,情况就不同了。query 作为第一个形参,实际上接受的是一个 React 打包的对象,长这样:

{
    query: ...,
    engine: ...
}

而且!这样子写是不会报错的,因为 JS 里的函数,调用参数无论传够了还是没够,甚至是多了,JavaScript 都不报错。(至少在主流浏览器实现上是这样)

这种逆天写法,换其他语言早就开始叫了,Python 会在运行时爆个 TypeError,编译型语言像 C/C++没等你运行编译器就先开始叫唤了,编译都过不去。

但 JavaScript 允许这种行为发生而没有任何提示!你参数传多了,就会按照实参的顺序依次给到形参(如果调用时没有指定哪个实参要给到哪个形参的话),剩下的就不管;你传少了,还是这样。函数里面要是引用没给到实参的形参咋办?那么你引用的那个形参的值就是 undefined,没了。就一个 undefined,甚至警告都不会有。

总结

因此,在定义 React 组件时,建议采用 (props) 或者 ({ prop1, prop2 }) 的形式,以避免潜在的问题。