unmountComponentAtNode
这个方法,并不陌生。
官方给出的解释是:
从 DOM 中卸载组件,会将其事件处理器(event handlers)和 state 一并清除。如果指定容器上没有对应已挂载的组件,这个函数什么也不会做。如果组件被移除将会返回 true,如果没有组件可被移除将会返回 false。
虽然在 React18
中,它已被 root.unmount()
取代。 但这不重要,项目目前的版本我也升不上去(历史原因)。
没想到,这两天还在这里栽了跟头,头大。
为什么这么说呢?看看下面的例子就明白了。
正常来说,unmountComponentAtNode
只会对ReactDOM.render
挂载在顶层的元素进行卸载。
效果看图:
root
下面有一个div
,点击卸载组件按钮之后,root
下面的div
不见了,说明卸载成功了。
具体代码如下:
// index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
// App.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Button } from 'antd';
const App = () => {
// 新增Dom
const addDom = () => {
const div = document.createElement('div');
div.innerHTML = '不可卸载组件'
document.getElementById('root').appendChild(div);
}
// 销毁组件
const destory = () => {
ReactDOM.unmountComponentAtNode(document.getElementById('root'));
}
return (
<div>
可卸载组件
<Button type="primary" style={{ margin: '0 8px'}} onClick={destory}>卸载组件</Button>
<Button type="primary" onClick={addDom}>新增DOM</Button>
</div>
)
}
export default App;
那如果我新增一个dom
节点,并且该节点并不是直接放在ReactDOM.render
里渲染的,而是通过appendChild
插入到root
下的。这个节点在我卸载root
的时候,会被卸载掉吗?
实际操作如下:
很明显,卸载不成功。这也是我踩坑的地方,如果想要插入的元素也被卸载掉,可以插入到App.js
的节点中,不要直接插入到根节点。
总之,unmountComponentAtNode
只对ReactDOM.render
挂载在顶层的组件才生效,其余无关render
方法永远返回的都是false
。
最后,附上React18
的版本(效果同上):
// index.js
import { createRoot } from 'react-dom/client';
import App from './App';
const container = document.getElementById('root');
const root = createRoot(container);
root.render(<App root={root} />);
// App.js
import React from 'react';
import { Button } from 'antd';
const App = (props) => {
const { root } = props;
// 新增Dom
const addDom = () => {
const div = document.createElement('div');
div.innerHTML = '不可卸载组件'
document.getElementById('root').appendChild(div);
}
// 销毁组件
const destory = () => {
root.unmount();
}
return (
<div>
可卸载组件
<Button type="primary" style={{ margin: '0 8px'}} onClick={destory}>卸载组件</Button>
<Button type="primary" onClick={addDom}>新增DOM</Button>
</div>
)
}
export default App;