【问题标题】:Modal component renders Twice on open模态组件在打开时呈现两次
【发布时间】:2019-10-15 07:23:04
【问题描述】:

我正在使用 react-spring 为基于 @reach/dialog 的 Modal 设置动画。模态可以有任何孩子。在孩子们中,我正在根据一些道具获取一些数据。

问题是在打开模式时进行了两次 fetch 调用。我认为这可能与我如何管理状态有关,这会导致重新渲染。

我尝试过在 modal 中记忆孩子,但没有成功,所以我认为问题出在 Modal 组件之外。

这里有一些接近我的代码以及它是如何工作的https://codesandbox.io/s/loving-liskov-1xouh

编辑:我已经知道如果我删除 react-spring 动画,则不会发生双重渲染,但我想尝试保持动画完整。

你认为你能帮我找出错误在哪里吗? (也非常感谢一些关于使用钩子的良好实践的提示)。

【问题讨论】:

  • 它没有被调用两次,api请求使它看起来像被调用了两次。
  • @JuniusL。不是它被调用了两次,我认为这是不止一次发生的渲染。如果我使用 React Devtools 对 Modal 进行分析,它会在打开和关闭的循环中在 Modal 组件中显示总共 5 个渲染。
  • 我尝试在孩子身上使用 React.memo 但结果是一样的 @filipe 。 React.PureComponent 有什么不同?

标签: reactjs react-hooks react-spring


【解决方案1】:

我检查了一下,因为动画完成时模态组件中的动画,它被渲染了两次,当我注释掉负责动画的片段时,模态被第二次渲染,模态只渲染一次。

 const Modal = ({ children, toggle, isOpen }) => {
  // const transitions = useTransition(isOpen, null, {
  //   from: { opacity: 0 },
  //   enter: { opacity: 1 },
  //   leave: { opacity: 0 }
  // });
  console.log("render");
  const AnimatedDialogOverlay = animated(DialogOverlay);
  // return transitions.map(
  //   ({ item, key, props }) =>
  //     item && (
    return (
        <AnimatedDialogOverlay isOpen={isOpen}>
          <DialogContent>
            <div
              style={{
                display: `flex`,
                width: `100%`,
                alignItems: `center`,
                justifyContent: `space-between`
              }}
            >
              <h2 style={{ margin: `4px 0` }}>Modal Title</h2>
              <button onClick={toggle}>Close</button>
            </div>
            {children}
          </DialogContent>
        </AnimatedDialogOverlay>
    );
  //     )
  // );
};

【讨论】:

  • 感谢您的时间和您的回复,遗憾的是我已经知道这一点,我希望找到一个保持动画的解决方案。我将编辑问题以更好地反映这一点
【解决方案2】:

它渲染了三次,因为你的返回组件有transitions.map,因为你在里面有三个项目

    from: { opacity: 0 }
    enter: { opacity: 1 }
    leave: { opacity: 0 }

{children}isOpen 为真时被调用了两次 您只需删除 from: { opacity: 0 }leave: { opacity: 0 } 即可解决此问题

所以改变你的 modal.js => transitions

  const transitions = useTransition(isOpen, null, {    
    enter: { opacity: 1 }
  });

【讨论】:

  • 正如你所说的,问题是每次更新都会渲染孩子。为了维持动画,我最终使用了转换保持的状态变量和 {state==="update" &amp;&amp; children} 。现在我只需要检查如何在进入/离开时更改高度。谢谢!!!
【解决方案3】:

问题是,在动画结束时,AnotherComponent 会重新挂载。我读过关于 react-spring 的类似问题。一种方法是,您将状态从 AnotherComponent 提升到 index.js。这样状态不会在重新挂载时丢失,并且您可以防止重新获取数据。

const AnotherComponent = ({ url, todo, setTodo }) => {
  useEffect(() => {
    if (todo.length === 0) {
      axios.get(url).then(res => setTodo(res.data));
    }
  });
....
}

这是我的版本:https://codesandbox.io/s/quiet-pond-idyee

【讨论】:

  • 我真的很喜欢这个解决方案,但我无法从孩子身上提取逻辑,因为他负责提取(在实际代码中,他收到一个 ID 来进行提取)。但无论如何,谢谢。它可能会帮助我思考一个抽象。
猜你喜欢
  • 1970-01-01
  • 2022-11-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-02
  • 1970-01-01
  • 2022-11-26
相关资源
最近更新 更多