Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/reactjs/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Reactjs React门户能否用于无状态功能组件(SFC)?_Reactjs - Fatal编程技术网

Reactjs React门户能否用于无状态功能组件(SFC)?

Reactjs React门户能否用于无状态功能组件(SFC)?,reactjs,Reactjs,我在有状态组件的呈现方法中使用了ReactDOM.createPortal,如下所示: class MyComponent extends Component { ... render() { return ( <Wrapper> {ReactDOM.createPortal(<FOO />, 'dom-location')} </Wrapper>

我在有状态组件的呈现方法中使用了
ReactDOM.createPortal
,如下所示:

class MyComponent extends Component {
    ...
    render() {
        return (
            <Wrapper>
                {ReactDOM.createPortal(<FOO />, 'dom-location')}
            </Wrapper>
        )
    }
}
类MyComponent扩展组件{
...
render(){
返回(
{ReactDOM.createPortal(,'dom location')}
)
}
}
。。。但是它也可以被无状态(功能)组件使用吗?

是的,根据主要要求是:

第一个参数(子参数)是任何可呈现的子参数,如元素、字符串或片段。第二个参数(容器)是DOM元素

在无状态组件的情况下,您可以通过道具传递元素,并通过门户呈现它


希望有帮助。

对于固定组件,可以这样做:

const X = ({ children }) =>  ReactDOM.createPortal(children, 'dom-location')
const MyComponent = () => ReactDOM.createPortal(<FOO/>, 'dom-location')
无状态(功能)组件也可以使用它吗 ?

内部渲染:

render() {
    const modal = this.state.showModal ? (
      <Modal>
        <Hello/>
        </Modal>
    ) : null;

    return (
      <div>
      <div id="myEle">
        </div>
      </div>
    );
  }
render(){
const modal=this.state.showModal(
):null;
返回(
);
}

如果您不想手动更新index.html并添加额外的标记,则使用

时会出现一个选项,此代码段将为您动态创建一个div,然后插入子项

export const Portal=({children,className='root Portal',el='div'})=>{
const[container]=React.useState(document.createElement(el))
container.classList.add(className)
React.useffect(()=>{
document.body.appendChild(容器)
return()=>{
document.body.removeChild(容器)
}
}, [])
返回ReactDOM.createPortal(子对象、容器)
}
SSR门户(NextJS) 如果您试图将上述任何一项用于SSR(例如NextJS),您可能会遇到困难

以下内容应该能满足您的需要。此方法允许传递用于门户的id/选择器,这在某些情况下可能会有所帮助,否则它将使用
\uuuuuuuuroot\uuuportal\uuuuuu
创建默认值

如果找不到选择器,它将创建并附加一个div

注意:如果再次使用NextJS,还可以静态添加div并在
页面/\u document.tsx
(或.jsx)中指定已知id。传入该id,它将尝试查找并使用它

import { PropsWithChildren, useEffect, useState, useRef } from 'react';
import { createPortal } from 'react-dom';

export interface IPortal {
  selector?: string;
}

const Portal = (props: PropsWithChildren<IPortal>) => {

  props = {
    selector: '__ROOT_PORTAL__',
    ...props
  };

  const { selector, children } = props;

  const ref = useRef<Element>()
  const [mounted, setMounted] = useState(false);

  const selectorPrefixed = '#' + selector.replace(/^#/, '');

  useEffect(() => {

    ref.current = document.querySelector(selectorPrefixed);

    if (!ref.current) {
      const div = document.createElement('div');
      div.setAttribute('id', selector);
      document.body.appendChild(div);
      ref.current = div;
    }

    setMounted(true);

  }, [selector]);

  return mounted ? createPortal(children, ref.current) : null;

};

export default Portal;
从'react'导入{PropsWithChildren,useffect,useState,useRef};
从'react dom'导入{createPortal};
导出接口IPortal{
选择器?:字符串;
}
const Portal=(props:PropsWithChildren)=>{
道具={
选择器:“\uuuu根目录\uuuu门户”,
…道具
};
常量{selector,children}=props;
const ref=useRef()
const[mounted,setMounted]=useState(false);
常量selectorPrefixed=“#”+选择器。替换(/^#/,”);
useffect(()=>{
ref.current=document.querySelector(selector或refix);
如果(!ref.current){
const div=document.createElement('div');
div.setAttribute('id',选择器);
文件.正文.附件(div);
参考电流=div;
}
设置已安装(真);
},[选择器];
返回装载?createPortal(子项,参考当前):空;
};
导出默认门户;
用法 下面是一个使用门户的快速示例。它没有考虑到位置等,只是简单地告诉你使用方法。天空是无限的:)

import React,{useState,cssprroperties}来自“React”;
将门户从“./path/导入到/Portal';//上面的路径
const modalStyle:csp属性={
填充:“3rem”,
背景颜色:“#eee”,
边距:“0自动”,
宽度:400
};
常量Home=()=>{
const[visible,setVisible]=useState(false);
返回(
你好,世界

{可见?你好模式!:null} ); }; 导出默认主页;
TSX版本基于@Samuel的回答(React 17,TS 4.1):

//portal.tsx
从“React”导入*作为React
从“react dom”导入*作为react dom
接口IProps{
类名?:字符串
el?:字符串
子项:React.ReactNode
}
/**
*基于https://stackoverflow.com/a/59154364
*@param children子元素
*@param className CSS className
*@param el要创建的HTML元素。默认值:div
*/
const Portal:React.FC=({children,className,el='div'}:IProps)=>{
const[container]=React.useState(document.createElement(el))
if(类名)
container.classList.add(className)
React.useffect(()=>{
document.body.appendChild(容器)
return()=>{
document.body.removeChild(容器)
}
}, [])
返回ReactDOM.createPortal(子对象、容器)
}
导出默认门户

是的,但正如@Denys Kotsur告诉我们的那样,将元素作为子元素通过道具创建是更好的方法。一行代码片段并不能提供完整的答案。对于任何给定的答案,详细阐述都是非常受欢迎的。我不知道这为什么没有得到更多的关注。这是一个真正动态的、放得好的解决方案,可在许多不同的场景中重用!
render() {
    const modal = this.state.showModal ? (
      <Modal>
        <Hello/>
        </Modal>
    ) : null;

    return (
      <div>
      <div id="myEle">
        </div>
      </div>
    );
  }
import { PropsWithChildren, useEffect, useState, useRef } from 'react';
import { createPortal } from 'react-dom';

export interface IPortal {
  selector?: string;
}

const Portal = (props: PropsWithChildren<IPortal>) => {

  props = {
    selector: '__ROOT_PORTAL__',
    ...props
  };

  const { selector, children } = props;

  const ref = useRef<Element>()
  const [mounted, setMounted] = useState(false);

  const selectorPrefixed = '#' + selector.replace(/^#/, '');

  useEffect(() => {

    ref.current = document.querySelector(selectorPrefixed);

    if (!ref.current) {
      const div = document.createElement('div');
      div.setAttribute('id', selector);
      document.body.appendChild(div);
      ref.current = div;
    }

    setMounted(true);

  }, [selector]);

  return mounted ? createPortal(children, ref.current) : null;

};

export default Portal;
import React, { useState, CSSProperties } from 'react';
import Portal from './path/to/portal'; // Path to above

const modalStyle: CSSProperties = {
  padding: '3rem',
  backgroundColor: '#eee',
  margin: '0 auto',
  width: 400
};

const Home = () => {

  const [visible, setVisible] = useState(false);

  return (
    <>
      <p>Hello World <a href="#" onClick={() => setVisible(true)}>Show Modal</a></p>
      <Portal>
        {visible ? <div style={modalStyle}>Hello Modal! <a href="#" onClick={() => setVisible(false)}>Close</a></div> : null}
      </Portal>
    </>
  );

};

export default Home;
// portal.tsx
import * as React from 'react'
import * as ReactDOM from 'react-dom'

interface IProps {
    className? : string
    el? : string
    children : React.ReactNode
}

/**
 * React portal based on https://stackoverflow.com/a/59154364
 * @param children Child elements
 * @param className CSS classname
 * @param el HTML element to create.  default: div
 */
const Portal : React.FC<IProps> = ( { children, className, el = 'div' } : IProps ) => {
    
    const [container] = React.useState(document.createElement(el))
    
    if ( className )
        container.classList.add(className)

    React.useEffect(() => {
        document.body.appendChild(container)
        return () => {
            document.body.removeChild(container)
        }
    }, [])

    return ReactDOM.createPortal(children, container)
}

export default Portal