当我们更换conditionprops 时,有没有什么措施可以防止Widget组件被卸载并再次安装?

interface FooProps {
  condition:boolean
}

const Foo: React.FC<FooProps> = ({condition}) => {
  const widget = <Widget/>
  
  if(condition){
    return <ComponentA>{widget}</ComponentA>
  }
  
  return (
    <ComponentB>
      <ComponentC/>
      {widget}
    </ComponentC>
  )
}

推荐答案

它会卸载,因为该 node 不再存在于虚拟DOM中.你无法阻止这一点.

但是...

你可以弄些小把戏让它发挥作用

You can hide it via css

您可以通过display: none有条件地隐藏组件,而不是有条件地呈现组件.它将挂载组件两次,但如果条件改变,它不会在重现器之间卸载

Use common parent

如果元素在渲染器之间有相同的父元素,它将不会卸载.

 if (condition) {
    return <ComponentA><Widget key="widget"/></ComponentA>;
  }

  return (
    <ComponentA>
      <ComponentC />
      <Widget key="widget" /> 
    </ComponentA>
  );

<Widget key="widget" />key是必要的.因为来自ComponentA的子元素会编译成Reaction元素数组,所以使用key可以防止在元素顺序改变时卸载单个元素.在第一个条件Widget中是第一个元素,在第二个条件中是第二个元素

Use Portal

您可以将Widget附加到虚拟DOM的同一 node ,并使用portals呈现在您想要的任何位置

import { createPortal } from 'react-dom' 

const Example = () => {
    const [s, ss] = React.useState(true)
    return (
        <>
            <button onClick={() => ss((o) => !o)}>click</button>
            <Foo condition={s} />
        </>
    )
}

const Widget = () => {
    React.useEffect(() => {
        console.log('Widget mount')
    }, [])

    return <>widget</>
}

const ComponentA = ({ children }: { children: React.ReactElement }) => {
    React.useEffect(() => {
        console.log('ComponentA mount')
    }, [])

    return <>{children} inside component a</>
}

const ComponentC = ({ children }: { children: React.ReactElement }) => {
    React.useEffect(() => {
        console.log('ComponentC mount')
    }, [])

    return <>{children} inside component c</>
}

const Foo = ({ condition }: { condition: boolean }) => {
    const ref = React.useRef<any>()
    let content
    if (condition) {
        content = (
            <ComponentA>
                <div ref={ref} />
            </ComponentA>
        )
    } else {
        content = (
            <ComponentC>
                <div ref={ref} />
            </ComponentC>
        )
    }
    return (
        <>
            {content}
            <Portal
                dependency={[condition]}
                elementRef={ref}
            >
                <Widget />
            </Portal>
        </>
    )
}

const Portal = ({ elementRef, children, dependency = [] }: any) => {
    const el = React.useRef<any>()
    if (!el.current) {
        el.current = document.createElement('div')
    }

    React.useLayoutEffect(() => {
        const element = elementRef.current
        element.appendChild(el.current)
        return () => {
            element.removeChild(el.current)
        }
    }, dependency)  // we need to execute this again if the content changes

    return createPortal(children, el.current)
}

在此示例中,<Widget />:

  • Virtual DOM名中content名的sibling 姐妹
  • real DOM岁的content岁的子元素

在本例中,如果您单击按钮,它将更改内容,但小部件不会卸载

Reactjs相关问答推荐

在Redux工具包查询中,是否可以将标记应用到API切片内的所有端点?

滚动事件监听器在Next.js客户端组件中不触发

Reaction-路由v6动态路径RegExp

为什么登录错误和密码在创建Reaction-Hook-Form后立即被删除?

更改购物车中的产品数量后,PayPal Reaction/Next JS按钮未更新

为什么我的react虚拟化列表不显示滚动条,除非我确保高度低于rowCount*rowHeight?

Redux Store未触发React组件中的重新呈现

当我try 部署我的Reaction应用程序时,为什么在此PrevState语句中收到语法错误?

react ';S使用状态不设置新状态

获取更改后的状态值

React-React中是否完全支持基于类的组件?

如何获取用户在 GooglePlacesAutocomplete 中输入的文本?

Next.js 和理智 | npm run build 时预渲染页面/时发生错误

使用jest如何覆盖对象的模拟?我正在使用`jest.mock()`来模拟对象,并希望 for each 测试用例覆盖模拟.

Firebase Storage: 对象不存在图片上传路径错误

如何测试使用 React.createportal 呈现的组件?

如果传递给挂钩的数据需要事先修改,如何使用自定义挂钩?

在 Spring Cloud Gateway 中运行的 React SPA 页面刷新出现白标错误

如何制作基于对象 struct 呈现数据的可重用组件?

如何在react 日历中自定义带有圆形边框的日期项?