简体   繁体   English

在内部组件中使用钩子

[英]Using hooks in inner Component

I'm trying to create component with Hook, but I'm faced with a strange problem.我正在尝试使用 Hook 创建组件,但遇到了一个奇怪的问题。
I use mapbox-gl in my code.我在我的代码中使用 mapbox-gl。 In order to init mapbox-gl, I have to wait until dom component is loaded.为了初始化 mapbox-gl,我必须等到加载 dom 组件。 (useLayoutEffect or useEffect) (useLayoutEffect 或 useEffect)
There is no problem in the initial display, but when I push the button(L72), the canvas which is created by mapbox-gl is unmounted with no console error.初始显示没有问题,但是当我按下按钮(L72)时,mapbox-gl创建的canvas被卸载,没有控制台错误。
I tried to move MyMap component outside the Tile component(L35-L45), then the above problem wasn't happened.我试图将 MyMap 组件移到 Tile 组件(L35-L45)之外,然后没有发生上述问题。

Am I using Hook incorrectly?我是否错误地使用了 Hook?

My sample full code is following.我的示例完整代码如下。
[CodeSandbox] [代码沙盒]

This is an excerpt in Map.tsx:这是 Map.tsx 中的摘录:

export const Tile: React.FunctionComponent<PropsType> = ({
  mapComponentLoaded,
  trigger,
  triggered
}) => {
  const classes = useStyles({});

  React.useLayoutEffect(() => { // or useEffect
    // init mapbox-gl
    mapComponentLoaded();
  }, []); // run at once

  // it doesn't works. if you clicked the button, the canvas under div#map would unmount.
  const MyMap = (props: { triggered: boolean }) => (
    <Paper className={classes.content}>
      <div id="map" className={classes.map} />
      <Typography>{props.triggered ? "fired" : "not fired"}</Typography>
    </Paper>
  );

  return (
    <div className={classes.root}>
      <Grid container spacing={1} className={classes.root}>
        <Grid item xs={12}>
          <Button variant="contained" color="primary" onClick={() => trigger()}>
            Add Boundary
          </Button>
        </Grid>
        <Grid item xs={12} className={classes.map}>
          <MyMap triggered={triggered} />
        </Grid>
      </Grid>
    </div>
  );
};

Thanks.谢谢。

When you define a component inside a functional component, on each render a new reference of it is created and hence instead of re-rendering, react remounts it as it things a new component has been created当您在功能组件中定义一个组件时,在每次渲染时都会创建一个新的引用,因此不会重新渲染,而是重新安装它,因为它已经创建了一个新组件

When you take the component out of the functional component, the reference of the function doesn't change and hence react renders it correctly当您将组件从功能组件中取出时,function 的引用不会改变,因此 react 会正确呈现它

Now another way this would work is if instead of rendering MyMap as a component, you call it as a function.现在另一种可行的方法是,如果不是将MyMap渲染为组件,而是将其称为 function。

export const Tile: React.FunctionComponent<PropsType> = ({
  mapComponentLoaded,
  trigger,
  triggered
}) => {
  const classes = useStyles({});

  React.useLayoutEffect(() => { // or useEffect
    // init mapbox-gl
    mapComponentLoaded();
  }, []); // run at once

  // it doesn't works. if you clicked the button, the canvas under div#map would unmount.
  const MyMap = (props: { triggered: boolean }) => (
    <Paper className={classes.content}>
      <div id="map" className={classes.map} />
      <Typography>{props.triggered ? "fired" : "not fired"}</Typography>
    </Paper>
  );

  return (
    <div className={classes.root}>
      <Grid container spacing={1} className={classes.root}>
        <Grid item xs={12}>
          <Button variant="contained" color="primary" onClick={() => trigger()}>
            Add Boundary
          </Button>
        </Grid>
        <Grid item xs={12} className={classes.map}>
          {MyMap({triggered})}
        </Grid>
      </Grid>
    </div>
  );
};

Working demo with second approach使用第二种方法的工作演示

PS However taking the definition out of function definition is a much better approach as it gives you the flexibility to add more performance optimizations using React.memo and also to use hooks within this component PS然而,从 function 定义中取出定义是一种更好的方法,因为它使您可以灵活地使用React.memo添加更多性能优化,并在此组件中使用钩子

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM