reactDOM
前置
react-dom 提供了可在应用顶层使用的 DOM(DOM-specific)方法。
- render()
- hydrate()
- unmountComponentAtNode()
- findDOMNode()
- createPortal()
你可以使用以下命令在本地启动一个 node 服务器,运行本文的示例。
npm i create-react-app -g
create-react-app test --typescript --use-npm
npm start
render
render 有三个参数:
- 要渲染的 React 元素
- 元素挂载位置
- 在组件被渲染或更新之后被执行的回调
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root'),
() => {}
)
渲染机制:
- stack https://claudiopro.github.io/react-fiber-vs-stack-demo/stack.html
先比对再更新视图 - fiber https://claudiopro.github.io/react-fiber-vs-stack-demo/fiber.html
将比对拆分
hydrate
与 render() 相同,但它用于在 ReactDOMServer 渲染的容器中对 HTML 的内容进行 hydrate 操作。
unmountedComponentAtNode
从 DOM 中卸载组件,会将其事件处理器(event handlers)和 state 一并清除。如果指定容器上没有对应已挂载的组件,这个函数什么也不会做。如果组件被移除将会返回 true,如果没有组件可被移除将会返回 false。
ReactDOM.unmountComponentAtNode(document.getElementById('root') as HTMLElment)
document.getElementById('root') 可能返回 HTMLElment 或者 null ,ReactDOM.unmountComponentAtNode 不能接收 null,使用 as 强制指定。unmountComponentAtNode 卸载组件会走生命周期函数(卸载)。原生 js 的 remove() 不会走。
findDOMNode
如果组件已经被挂载到 DOM 上,此方法会返回浏览器中相应的原生 DOM 元素。此方法对于从 DOM 中读取值很有用,例如获取表单字段的值或者执行 DOM 检测(performing DOM measurements)。**
大多数情况下,你可以绑定一个 ref 到 DOM 节点上,可以完全避免使用 findDOMNode。**
findDOMNode 不能用于函数组件。
findDOMNode 是一个访问底层 DOM 节点的应急方案(escape hatch)。在大多数情况下,不推荐使用该方法,因为它会破坏组件的抽象结构。严格模式下该方法已弃用。
let app:any
ReactDOM.render(
<App ref={node=>app=node} />,document.getElementById('root'),
()=>{
console.log(app)
// 可以调用app组件原型链上的方法
app.componentWillUnmount()
// 获取dom元素
ReactDom.findDOMNode(app)
}
)
createPortal
创建 portal。Portal 将提供一种将子节点渲染到 DOM 节点中的方式,该节点存在于 DOM 组件的层次结构之外。
export default class Protal extents React.Component {
public state = {counter: 0}
increase() {
this.setState((prevState: any) => ({
counter: prevState.counter + 1
}))
}
reader(){
return{
<div id="father" onClick={this.increase.bind(this)}>
<div>counter: {this.state.counter}</div>
<button></button>
</div>
}
}
}
index.html
<div id="root"></div>
<div id="protal"></div>
将 Protal 组件挂载到 root,如何把 button 渲染到 protal?
方式一,通过 render
reader(){
ReactDOM.reader(<button>Click</button>. document.getElementById('protal'))
return{
<div id="father" onClick={this.increase.bind(this)}>
<div>counter: {this.state.counter}</div>
// <button></button>
</div>
}
}
使用 render,事件无法触发
方式二,createPortal
reader(){
return{
<div id="father" onClick={this.increase.bind(this)}>
<div>counter: {this.state.counter}</div>
// <button></button>
{ReactDOM.createPortal(<button></button>,document.getElementById('protal'))}
</div>
}
}
事件正常触发,react 在运行时依然将 button 作为 father 的子元素,这样事件依然可以冒泡触发。