React Router Dom v4 のサンプル https://reacttraining.com/react-router/web/example/auth-workflow を見ると、 PrivateRoute コンポーネントは以下のように rest prop を破壊していることがわかります。
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
にリネームして、Routeのrender
関数に渡されるプロップのネーミングの問題を回避できるようにします。
これでいいですか?
申し訳ありません、私の最初の回答は(できればまだ有用で追加的な文脈を提供したいのですが)あなたの質問の答えになっていないことに気づきました。もう1度確認させてください。
あなたの質問
コンポーネント、...残り}の意味を確認したいのです。Component, ...rest }
の意味です。
props
から、Component
プロパティを取得し、その他の与えられたprops
を全て取得します。 そして、props
をrest
にリネームして、props
のネーミングの問題を回避することができます。 そうすれば、Routeのrender
関数に渡されるprops
の名前の問題を回避できます。
あなたの解釈は全く正しくありません。しかし、あなたの考えに基づいて、ここで起こっていることがある種のオブジェクトの再構築に相当するという事実を少なくとも認識しているようです(より明確化するには、2番目の回答およびそのコメントをご覧ください)。
正確な説明をするために、{ component, ...rest }}を分解してみましょう。Component, ...rest }
式を2つの別々の操作に分解してみましょう。
1.1. 操作1: props
(Note: 小文字の component) に定義されている component
プロパティを見つけ、それを Component
(Note: 大文字の Component) と呼ぶ状態の新しいロケーションに割り当てます。
2.2. 操作2: 次に、props
オブジェクトに定義されているすべての残りのプロパティを取り出し、 rest
という引数の中にまとめます。
重要なのは、props
をrest
にリネームしていないことです。(また、Routeの render
関数に渡される props
の命名問題を回避しようとすることとも関係ありません").
rest === props;
// => false
これは、単に props
オブジェクトに定義されているプロパティの the rest (それゆえ、この引数はそのように名付けられています) を、 rest
という新しい引数に取り出しただけです。
const myObj = {
name: 'John Doe',
age: 35,
sex: 'M',
dob: new Date(1990, 1, 1)
};
この例では、props
はmyObj
と同じ構造(i.e. , プロパティと値)を持っていると考えるとよいでしょう。さて、次のような代入を書きましょう。
const { name: Username, ...rest } = myObj
上の文は、2つの変数(あるいは定数)の宣言と代入の両方に相当します。この文は次のように考えることができる。
myObjに定義されたプロパティ name
を受け取り、その値を Ubj
と呼ぶ新しい変数に代入します。
その値を Username
と呼ぶ新しい変数に代入します。次に、他のすべてのプロパティを取得します。
次に、myObj
に定義されている他のプロパティ (_i.e., age
, sex
, dob
) を取得し、それらをまとめて
を集めて、新しいオブジェクトを作成し、それを rest
という変数に代入します。
コンソールで Username
と rest
をログに記録すると、このことが確認できます。以下のようになります。
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]のドキュメント2がすべてそのように書かれているのには理由があります。つまり、JSXでレンダリングされたカスタムコンポーネントを大文字にすることは、それ自体が習慣というよりも、必要なことなのです。React、より正しくはJSXは大文字と小文字を区別するです。頭文字を大文字にしないで挿入されたカスタムコンポーネントは、DOMにレンダリングされません。これは、Reactがカスタムコンポーネントを識別するために定義した方法に過ぎません。したがって、もしこの例で props
から取り出した component
プロパティを Component
にリネームしていなかったら、 <component {...props} />
式は失敗していたでしょう。/>` 式は正しくレンダリングされないでしょう。
これにより、すべての props
を一つの簡潔な式で表現することができます。例えば、 PrivateRoute
コンポーネントが受け取る props
が以下のようなものだと仮定します。
// `props` Object:
{
thing1: 'Something',
thing2: 'Something else'
}
これらのアイテム(i.e., thing1
と thing2
) をさらにネストした <Component />
タグに渡したい場合、そして object spread 構文に精通していない場合は、次のように記述するかも知れません。
<Component
thing1={ props.thing1 }
thing2={ props.thing2 } />
しかし、{ ...props }
構文は、値の配列(., [...vals]
) と同じように props
オブジェクトを spread することができるため、このような冗長性を排除することができます。言い換えれば、以下のJSX式と上記のJSX式は全く等価です。
<Component { ...props } />
簡単に説明しましょう。javaScriptでは、キーと値のペアが同じであれば、obj={account:account}と同じになります。 obj={account:account}はobj={account}と同じです。つまり、親コンポーネントから子コンポーネントにpropsを渡す場合、以下のようになります。
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;
のように渡すと、残りのpropsは
label={label} placeholder={placeholder} type={type}