react createRoot和createPortal的用法和区别
那么我们有了这个根节点是不是就可以把我们的弹窗组件放到这个根节点里面呢?其实我们可以用这个来做很多的事情。这就是传统的创建react项目然后挂载到根节点的方式,和vue中的类似原理都是一样的,创建一个节点然后把这个节点渲染到根节点中。这样做你会发现你这个组件不灵活会被很多东西影响,比如你的父级元素有相对定位等等都会影响到你这个弹窗组件。这样生成的dom加载在body下,实现很多弹窗消息提示还有dr
·
createRoot 在浏览器的 DOM 节点中创建根节点以显示 React 组件。
import { createRoot } from 'react-dom/client';
import App from './App'
const domNode = document.getElementById('root');
const root = createRoot(domNode);
root.render(<App />)
这就是传统的创建react项目然后挂载到根节点的方式,和vue中的类似原理都是一样的,创建一个节点然后把这个节点渲染到根节点中。
这就是传统的vue渲染根节点的方法。两者得方式都是殊途同归的。
import { createApp } from 'vue';
import App from './App'
const domNode = document.getElementById('app');
const root = createApp(domNode);
root.render(<App />)
我们可以通过这个api来作什么?其实我们可以用这个来做很多的事情。比如我们现在有一个需求,我们点击一个按钮你要给我们一个弹窗的反馈。第一时间你会想到怎么去实现这个功能。
常见的我们会这样去做:
import {useState} from 'react'
const model=()=>{
const [show,setShow]= useState(false)
const Model=()=>{
return <>
//通过定位实现
<div></div>
</>
}
return (
<>
<button onClick={()=>{
setShow(!show)
}}>{!show?'显示':'隐藏'}</button>
{show&&<Model/}
</>
)
}
这样做你会发现你这个组件不灵活会被很多东西影响,比如你的父级元素有相对定位等等都会影响到你这个弹窗组件。
怎么才能做到不被影响呢?这就是这个createRoot函数的作用了。它可以创建一个节点这个节点创建出来就是一个根节点。那么我们有了这个根节点是不是就可以把我们的弹窗组件放到这个根节点里面呢?在根节点就不会被父级元素影响。
import {useState} from 'react'
import ReactDOM from 'react-dom/client';
const Model=(props)=>{
const [show,setShow]= useState(false)
//创建一个container
return (
<>
//通过定位实现
<div></div>
</>
)
}
const getContainer =()=>{
const container = document.createElement('div');
container.classList.add('container-model');//这个容器挂载到根节点到时候用来装弹窗组件
container.style.position='absolute';
document.body.appendChild(container);//加载到body
return container
}
//HOC这是高阶函数
const openModel=(type)=>('组件调用方法的传递参数的')=>{
const container = document.querySelector('container-model')
const divContent = document.createElement('div');
divContent.style.transition = '.3s';
divContent.style.marginTop = '16.0px';
if(container){
container.appendChild(divContent)
}else{
container = getContainer();
container.appendChild(divContent)
}
//在divContent这个容器之下 在创建一个根节点然后这个Model这个组件渲染在这个根节点之下
const root = ReactDOM.createRoot(divContent);
//在container这个容器之下 在创建一个根节点然后这个Model这个组件渲染在这个根节点之下
//divContent就不会显示的 在container这个根节点之后渲染这个Model组件
//const root = ReactDOM.createRoot(container);
root.render(<Model {...props}/>)
}
const open=openModel('可以定义类型')
export default {
openModel
}
这样创建的元素就会挂载到根节点container-model这个节点下面。
createPortal JSX 作为 children 渲染至 DOM 的不同部分。
// 组合的结果
cosnt Modal = (props)=> {
let divEle=null
useEffect(()=>{
divEle=document.createElement('div')
document.body.appendChild(divEle)
return ()=>{
document.body.removeChild(divEle)
}
},[])
render () {
// console.log('modal props', this.props)
const { visible, onCancel, prompt, width } = props
const close = ev => {
// 点击弹层空白处,隐藏弹框
// console.log('ev', ev.target.dataset.self)
if (ev.target.dataset.self) {
(typeof onCancel === 'function') && onCancel()
}
}
return ReactDOM.createPortal(
(
<div
className='layer'
//控制显示隐藏
style={{display:(visible?'block':'none')}}
data-self={true}
onClick={close}
>
<div
className='modal'
style={{
width: (prompt ? '420px' : `${width}px`),
marginLeft: (prompt ? '-210px' : `-${width/2}px`)
}}
>
{/* props穿透 */}
{ !prompt && <Header {...props} /> }
{ !prompt ? <Main {...props} /> : <Prompt {...props} /> }
{ !prompt && <Footer {...props} /> }
</div>
</div>
), divEle
)
}
}
export default Modal
这样生成的dom加载在body下,实现很多弹窗消息提示还有draw这样的组件都可以采用这样的方式。
createRoot这个更适合做一些type类型的组件比如message等等。
更多推荐
已为社区贡献8条内容
所有评论(0)