在使用React中,你是否會出現過一個文件的代碼不少,既存在應用數據的讀取和處理,又存在數據的顯示,並且每一個組件還不能複用。html
首先咱們來看一個容器組件和展現組件一塊兒的例子吧。react
class TodoList extends React.Component{ constructor(props){ super(props); this.state ={ todos:[] } this.fetchData = this.fetchData.bind(this); } componentDidMount(){ this.fetchData(); } fetchData(){ fetch('/api/todos').then(data =>{ this.setState({ todos:data }) }) } render(){ const {todos} = this.state; return (<div> <ul> {todos.map((item,index)=>{ return <li key={item.id}>{item.name}</li> })} </ul> </div>) } } 複製代碼
你們能夠看到這個例子是沒有辦法複用的,由於數據的請求和數據的展現都在一個組件進行,要實現組件的複用,咱們就須要將展現組件和容器組件分離出來。api
具體代碼以下:數組
//展現組件 class TodoList extends React.Component{ constructor(props){ super(props); } render(){ const {todos} = this.props; return (<div> <ul> {todos.map((item,index)=>{ return <li key={item.id}>{item.name}</li> })} </ul> </div>) } //容器組件 class TodoListContainer extends React.Component{ constructor(props){ super(props); this.state = { todos:[] } this.fetchData = this.fetchData.bind(this); } componentDidMount(){ this.fetchData(); } fetchData(){ fetch('/api/todos').then(data =>{ this.setState({ todos:data }) }) } render(){ return (<div> <TodoList todos={this.state.todos} /> </div>) } } 複製代碼
當咱們把組件分離成容器組件和展現組件這兩類時,你會發現他們可以很方便的實現複用。性能優化
Page,Header,Sidebar,UserInfo,Listbash
UserPage, FollowersSidebar, StoryContainer, FollowedUserListmarkdown
我建議你從開始建立組件時只使用展現組件,到最後會意識到你傳遞了不少props到中間組件,而這些中間組件根本不會用到他們接收到的這些props,僅僅是向下傳遞。而當這些子組件須要更多的數據時,你須要重新配置這些中間組件。這個時候就須要引入容器組件了。使用容器組件的方式,您能夠將數據和行爲經過props傳遞給葉子組件,而沒必要麻煩一些不相關的中間組件。less
這是一個重構的過程,因此不比在第一次就作對。當你嘗試這種模式。在什麼時候應抽取爲容器組件你將會有一種直觀的感受。就像您知道什麼時候抽取函數同樣ide
重要的是你須要明白容器組件和展現組件之間不是技術上的區別,而是目的上的區別。函數
相比之下,這裏有幾個相關的(但不一樣的)技術區別:
有狀態【Stateful】和 無狀態【Stateless】:
容器組件傾向於有狀態,展現組件傾向於無狀態,這不是硬性規定,由於容器組件和展現組件均可以是有狀態的。
類【Classes】 和 函數【Functions】:
組件能夠被申明成類或函數,函數組件定義簡單,可是他缺少目前僅用於類的一些功能。雖然函數組件有不少限制,可是直到如今還有人使用,是由於函數組件容易理解,建議在不須要本身的state,lifecycle hooks,或性能優化的狀況下使用函數組件。這些僅適用於類組件。
//咱們將上邊的展現組件改寫成函數組件能夠以下 function TodoList(props){ return (<div> <ul> {props.todos.map((item,index)=>{ return <li key={item.id}>{item.name}</li> })} </ul> </div>) } 複製代碼
可能不少人不清楚函數組件和類組件的區別,能夠去React的官網看一下函數組件和類組件
純粹【Pure】 和 不純粹 【Impure】:
純粹:輸入什麼就輸出什麼,不會再其中作相應的變更。能夠被定義爲類或函數,能夠是無狀態或有狀態的,純組件的另外一個重要方面是它們不依賴props或state中的深度變更,因此他們的渲染性能能夠經過在shouldComponentUpdate()鉤子中進行淺層比較來優化,當前只有類能夠定義shouldComponentUpdate()方法。
不論是展現組件仍是容器組件都會有上面的二分特性。在我看來,展現組件每每是沒有狀態的純函數,而容器組件每每是有狀態的純類,這僅僅我的觀點並不是規則。
當不重要或說很難分清時,不要把分離容器組件和展現組件當作教條, 若是你不肯定該組件是容器組件仍是展現組件是,就暫時不要分離,寫成展現組件吧。
譯文來源:https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0