若是React在更新中只重用与元素类型相匹配的宿主实例,那按渲染条件选择的内容怎么办呢?
正以下面的代码,假如咱们开始至须要一个input
,但稍后须要在它以前渲染一个message
:
// 第一次渲染 ReactDOM.render( <dialog> <input /> </dialog>, domContainer ); // 第二次渲染 ReactDOM.render( <dialog> <p>I was just added here!</p> <input /> </dialog>, domContainer );
在这个例子中,<input>
宿主实例将会被重建。React会遍历元素树,并与以前的版本比较:app
input
,并建立新的p
宿主实例。React这样的代码是以下的:dom
let oldInputNode = dialogNode.firstChild; dialogNode.removeChild(oldInputNode); let pNode = document.createElement('p'); pNode.textContent = 'I was just added here!'; dialogNode.appendChild(pNode); let newInputNode = document.createElement('input'); dialogNode.appendChild(newInputNode);
这不是一种好的更新方式,由于原则上input
并无被p
替代-它仅仅是移动了。咱们不想要由于从新建立Dom元素而失去它的选中状态,聚焦状态和显示内容。
幸亏这个问题有一个简单的修复方式,他并不在React应用中常见。
在实践中,你不多会直接调用ReactDOM.render
,实际上,React app经常会拆分红像下面这样的函数:函数
function Form({ showMessage }) { let message = null; if (showMessage) { message = <p>I was just added here!</p>; } return ( <dialog> {message} <input /> </dialog> ); }
This example doesn’t suffer from the problem we just described. It might be easier to see why if we use object notation instead of JSX. Look at the dialog child element tree:
这个例子并不会有咱们以前描述的那个问题,若是咱们使用对象来代替JSX描述会更加明显,下面是dialog子元素树:code
function Form({ showMessage }) { let message = null; if (showMessage) { message = { type: 'p', props: { children: 'I was just added here!' } }; } return { type: 'dialog', props: { children: [ message, { type: 'input', props: {} } ] } }; }
function Form({ showMessage }) {
let message = null;
if (showMessage) {orm
message = { type: 'p', props: { children: 'I was just added here!' } };
}
return {对象
type: 'dialog', props: { children: [ message, { type: 'input', props: {} } ] }
};
}element
无论showMessage 是true的仍是false,<input>
是第二个子元素,而且在render中不会改变它的位置。
若是showMessage 从false变为true,React会遍历元素树,并与以前的版本相比较:rem
那么React会执行相似于下面的代码:input
let inputNode = dialogNode.firstChild; let pNode = document.createElement('p'); pNode.textContent = 'I was just added here!'; dialogNode.insertBefore(pNode, inputNode);
input的状态并不会改变io