Level 6: 該一層一層傳下去嗎?
Closed this issue · 1 comments
kalun1988 commented
TodoHeader.js
裡的
<h1>{title}</h1>
由TodoApp.js
的
<TodoHeader
title="我的待辦清單"
username="Jason"
todoCount={99}
/>
傳入去,
那如果再由出一層的index.html傳入去,是不是要改為
TodoApp.js
<TodoHeader
title="{toDoHeaderTitle}"
username="Jason"
todoCount={99}
/>
index.html
const props = {
title: '我的待辦清單'
};
ReactDOM.render(
<TodoApp {...props} />,
document.getElementById('app')
);
有更好的做法嗎?
shiningjason commented
嗨,@kalun1988,這問題有下列五種方式可以解決:
ㄧ. 如同你的做法,一層一層傳下去
好處是比較明確,不過太多層會迷路!
二. 將一整包 props 傳下去
好處是 TodoApp 不須特別再寫一次要傳遞哪些 props;不過底層元件要追有哪些 props 時,還是會迷路!
/* index.js */
ReactDOM.render(
<TodoApp title="我的待辦清單" username="Jason" todoCount={99} />,
document.getElementById('app')
);
/* TodoApp.js */
render() {
return (
<div>
<TodoHeader {...this.props} />
</div>
)
}
/* TodoHeader.js */
render() {
return (
<div>
<h1>{this.props.title}</h1>
</div>
)
}
補充 1. 你也可以在 TodoApp 中,覆蓋上層元件傳遞的 props
/* TodoApp.js */
render() {
return (
<div>
<TodoHeader {...this.props} title="工作清單" />
</div>
)
}
補充 2. 或是在 TodoApp 中,給予預設的 props
/* TodoApp.js */
render() {
return (
<div>
<TodoHeader title="預設清單" {...this.props} />
</div>
)
}
三. 使用 Object rest properties 將 props 拆解
這方法通常用於你不想把多餘的 props 傳遞到子元件時!
/* index.js */
ReactDOM.render(
<TodoApp title="我的待辦清單" username="Jason" todoCount={99} todos={[]} />,
document.getElementById('app')
);
/* TodoApp.js */
render() {
// 如果我不想讓 TodoHeader 接到 todos 時
const { todos, ...rest } = this.props;
return (
<div>
<TodoHeader {...rest} />
</div>
)
}
/* TodoHeader.js */
render() {
return (
<div>
<h1>{this.props.title}</h1>
</div>
)
}
四. 使用 context
這做法通常用於你是要傳遞整個應用程式共用的資料或函數,例如:theme, 多國語言包, 登入/登出, navigation 等。
/* TodoApp.js */
class TodoApp extends React.Component {
getChildContext() {
return {
username: 'Jason' // 1. 假設登入者名稱會用在很多底層元件
};
}
// ...
}
TodoApp.childContextTypes = {
username: React.PropTypes.string
};
/* TodoHeader.js */
// 2. 假設 TodoHeader 是在 TodoApp -> ... -> ... -> 好幾層元件以下
class TodoHeader extends React.Component {
render() {
return (
<div>
<h1>{this.context.username}</h1>
</div>
);
}
}
TodoHeader.contextTypes = {
username: React.PropTypes.string
};
Ps. 不過官方不推薦該用法,因為唯有明確的傳遞 props 才會好維護!
參考連結
五. 實務用法
當你使用 Flux or Redux 和 container pattern 後~
class TodoApp extends React.Component {
render() {
// 1. 不用傳遞 props:
// 使用 Flux or Redux 後,所有業務資料和應用狀態將會存在它們系統中,而不是上層元件
return <TodoHeaderContainer />;
}
}
/* TodoHeaderContainer.js */
// 2. 加入 Container 元件:
// Container 元件用在跟 Flux or Redux 同步資料,
// 並且存在自身的 state 中,
// 然後每次 render 將 state 資料再傳遞到 View 元件中
class TodoHeaderContainer extends React.Component {
// ...省略詳細用法
render() {
return <TodoHeader title={this.state.title} />;
}
}
/* TodoHeader.js */
class TodoHeader extends React.Component {
render() {
return (
<div>
<h1>{this.props.title}</h1>
</div>
);
}
}
所以之後實際專案中,架構是長這樣的:
├── TodoApp.js
│ ├── TodoHeaderContainer.js
│ │ ├── TodoHeader.js
│ ├── TodoListContainer.js
│ │ ├── TodoList.js
│ ├── Footer.js
│ │ ├── TodoHeaderContainer.js
│ │ │ ├── TodoHeader.js
好處是
- TodoHeader, TodoList 等 View 元件的職責,只有拿 props 顯示資料
- TodoHeaderContainer, TodoListContainer 等 container 元件的職責,就是跟與 Flux or Rdeux 拿資料,並且傳遞資料給下層元件;所以當往後拿資料的方式變了,你只需換掉 container 元件即可
_回到你的問題,如果只是這樣簡單的範例,我認為目前一層一層傳下去是比較適當的!_
PS.
希望有幫助到你!也謝謝你提供我 feedback~!
如果上方有任何不明瞭的地方,歡迎你再給我意見囉!