若是咱們在同一個容器中使用兩次ReactDOM.render()
會發生什麼?app
ReactDOM.render( <button className="blue" />, document.getElementById('container') ); // ... later ... // 應該替換掉 button 宿主實例嗎? // 仍是在已有的 button 上更新屬性? ReactDOM.render( <button className="red" />, document.getElementById('container') );
再次說明,React的工做是使宿主樹和提供的React元素的樹一致。肯定宿主樹怎麼樣來響應新的信息的這個過程被稱爲協調。
協調有兩種方法。React的簡單的版本是拋棄已經存在的樹,從新創建新的樹:dom
let domContainer = document.getElementById('container'); // 清除樹 domContainer.innerHTML = ''; // 建立新的宿主樹 let domNode = document.createElement('button'); domNode.className = 'red'; domContainer.appendChild(domNode);
可是在DOM中,這是低效的,而且會丟失一些重要的信息像聚焦狀態,選中狀態,滾動狀態等等。因此咱們但願React像下面同樣工做:code
let domNode = domContainer.firstChild; // Update existing host instance domNode.className = 'red';
換句話說,React須要決定那時候須要更新一個已經存在的宿主實例來響應新的React元素,那時候須要新建一個宿主實例。
這就提出了關於分別的問題,React的元素可能一直在變化,那理論上那時候引用同一個宿主實例呢?
在咱們的例子上是很簡單的。咱們已經建立了一個<button>
做爲第一個(也是惟一一個)子元素,而且咱們但願在同一個地方再次渲染一個<button>
。咱們已經有一個<button>
的宿主實例,咱們就不須要再建立新的,再次使用它就行了。rem
這個已經與React的思想很是接近了。
若是元素的種類在樹的同一個地方以前一次的渲染和接下來的渲染是相同的,React會再次使用已經存在的宿主實例。
下面是React帶有備註的大體實現過程:get
// let domNode = document.createElement('button'); // domNode.className = 'blue'; // domContainer.appendChild(domNode); ReactDOM.render( <button className="blue" />, document.getElementById('container') ); // 能夠再次使用嗎? Yes! (button → button) // domNode.className = 'red'; ReactDOM.render( <button className="red" />, document.getElementById('container') ); // 能夠再次使用嗎? No! (button → p) // domContainer.removeChild(domNode); // domNode = document.createElement('p'); // domNode.textContent = 'Hello'; // domContainer.appendChild(domNode); ReactDOM.render( <p>Hello</p>, document.getElementById('container') ); // 能夠再次使用嗎? Yes! (p → p) // domNode.textContent = 'Goodbye'; ReactDOM.render( <p>Goodbye</p>, document.getElementById('container') );
這套規則對子樹也一樣適用。例如,當咱們在更新有兩個<button>
子組件時的<dialog>
,React首先決定是否重用<dialog>
,
而後再對每個子組件進行相同的過程。class