这是什么意思……在React JSX中休息


82

看一下这个React Router Dom v4示例https://reacttraining.com/react-router/web/example/auth-workflow我看到PrivateRoute组件像这样破坏了一个休息道具

const PrivateRoute = ({ component: Component, ...rest }) => (
  <Route {...rest} render={props => (
    fakeAuth.isAuthenticated ? (
      <Component {...props}/>
    ) : (
      <Redirect to={{
        pathname: '/login',
        state: { from: props.location }
      }}/>
    )
  )}/>
)

我想确定这{ component: Component, ...rest }意味着:

从中props获取Component属性,然后再提供所有其他属性,然后重命名props为,rest这样您就可以避免传递给Routerender函数的属性的命名问题

我对吗?


Answers:


156

抱歉,我意识到我的第一个答案(虽然希望仍能提供有用的/附加的上下文)不能回答您的问题。让我再尝试一次。

你问:

我想确定这{ component: Component, ...rest }意味着:

从中props获取Component道具,然后获取其他所有道具props重命名props为,rest这样您就可以避免props传递给Routerender函数的命名问题

您的解释不太正确。但是根据您的想法,听起来您至少知道以下事实:这里发生的事情构成某种对象破坏(请参阅第二个答案和评论以获取更多说明)。

为了给出准确的解释,让我们分解一下 { component: Component, ...rest }表达式分解为两个单独的操作:

  1. 操作1:找到component属性定义上props注意:小写Ç omponent)并将其分配给在状态中,我们调用一个新的位置Component:资本Ç omponent)。
  2. 操作2:然后,采取所有剩余的已定义的属性props对象并将它们收集在称为的参数中rest

重要的一点是您不会重命名propsrest。(而且,与“避免props传递给Route的命名问题也没有关系render函数的”有关。)

rest === props;
// => false

您只需将对象上定义的属性的其余部分(因此将其命名为该参数)转换为名为props的新参数rest


用法示例

这是一个例子。假设我们有一个如下定义的对象“ myObj”:
const myObj = {
  name: 'John Doe',
  age: 35,
  sex: 'M',
  dob: new Date(1990, 1, 1)
};

对于此示例,可能会想像一下props具有相同的结构(属性和值),可能会有所帮助myObj。现在,让我们编写以下任务。

const { name: Username, ...rest } = myObj

上面的声明相当于两个变量(或者,我想是常量)的声明赋值。该语句可以认为是:

接受name定义的属性,myObj并将其值分配给我们称为的新变量Username。然后,取中定义的任何其他属性myObjagesexdob),并收集他们到分配给变量我们名称的新对象rest

登录Usernamerestconsole会证实这一点。我们有以下内容:

console.log(Username);
// => John Doe
console.log(rest);
// => { age: 35, sex: 'M', dob: Mon Jan 01 1990 00:00:00 GMT-0800 (PST) }

边注

您可能想知道:

为何要撤出该component财产而只Component用大写字母“ C”重命名呢?

是的,这似乎很琐碎。而且,尽管这是标准的React惯例,但有理由将Facebook框架上的所有文档都照这样编写。即,大写使用JSX渲染的自定义组件本身不是一种实践,而是一种必要。React,或更恰当地说,JSX是区分大小写的。插入的没有大写首字母的自定义组件不会呈现给DOM。这就是React定义自己以识别自定义组件的方式。因此,如果该示例未另外重命名从中删除的component属性,则该表达式将无法正确呈现。propsComponent<component {...props} />


5
对我们努比亚人来说是伟大的移植!
user2763557 '19

13

它使您可以props在一个简洁的表达式中“扩展”所有内容。例如,假设props您的PrivateRoute组件收到的内容类似于

// `props` Object:
{
  thing1: 'Something',
  thing2: 'Something else'
}

如果你想进一步的手从这些项目(thing1thing2)下降到嵌套的<Component />标签和你不熟悉的物体传播语法,你可能会这样写:

<Component
  thing1={ props.thing1 }
  thing2={ props.thing2 } />

但是,{ ...props }语法允许您避免了这种冗长传播你的props对象以相同的方式一个可能蔓延值(数组例如[...vals])。换句话说,下面的JSX表达式和上面的JSX表达式完全等效。

<Component { ...props } />

1
关联时,请勿将JSX的扩展语法与rest属性
Felix Kling

3
“它允许您以一个简洁的表达方式“传播”所有道具。” 那是不对的。...restin{ component: Component, ...rest } 收集对象中的所有其他属性rest。问题是关于...rest,而不是{...props}
Felix Kling

正如Felix所指出的那样,JSX中的(非标准)对象扩展运算符与ECMAScript 2015规范中定义的rest _ / _ spread运算符之间存在区别。一方面,{ ...myObj }在非反应环境(例如,浏览器控制台)中尝试编写类似内容将引发SyntaxError。尽管如此,ES6的rest _ / _ spread提供了一个有用的概念框架,可以在其中考虑JSX的对象传播
IsenrichO

4

让我们保持简单:在JavaScript中,如果“键:值”对相同, obj={account:account}则与相同obj={account}。因此,当道具从父组件传递到子组件时:

const Input = ({name,label,error, ...rest}) => {
  return (
    <div className="form-group">
      <label htmlFor={name}>{label}</label>
      <input
        {...rest}
        autoFocus
        name={name}
        id={name}
        className="form-control"
        aria-describedby="emailHelp"
      />
    </div>
  );
};
export default Input;

您将通过以下其他道具

label={label} placeholder={placeholder} type={type}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.