React Spring 在组件已经更新后使用 React Context 进行动画转换

React Spring Transition with React Context animates after component has already updated

我有一个 React 组件,它应该订阅 React 上下文并呈现一些文本。 当上下文更新时,文本应该更新,但是当发生此更新时,我想用旧值动画组件,并用新值动画它。 我是 React Spring 的新手,但我认为他们的 Render-props API 中的 Transition 会在这里发挥作用,分别在挂载和卸载时触发动画事件。

From、Enter 和 Leave 似乎有效,并且当上下文改变时动画会播放,但是它会先改变上下文的内容,然后同时渲染旧元素的“Enter -> Leave”在新元素上呈现“From -> Enter”,导致在“旧元素”离开时出现重复的元素和不正确的文本。

我的想法告诉我,我需要更好地利用生命周期来处理重复的元素,并且可能使用来自父组件的 props 抽象上下文值而不是直接使用上下文值,但我可能已经死了这里错了。

所以,我的问题是如何让离开动画播放旧文本值,然后播放使用新文本值的进入动画,并且一次只显示一个元素?

此外,这是我的第一个问题,所以如果我做错了,请告诉我。

const TextComponent = () => {
  const contextData = useContext(Context);

  return (
    <Transition
      items={contextData.textToRender}
      from={{ opacity: 0, transform: 'translate3d(0%, -15%, 0)' }}
      enter={{ opacity: 1, transform: 'translate3d(0%, 0%, 0)' }}
      leave={{ opacity: 0, transform: 'translate3d(-15%, 0%, 0)' }}
    >
      {(condition) =>
        condition &&
        ((styles) => (
          <div style={styles}>
            <p className='station-text'>{contextData.textToRender}</p>
          </div>
        ))
      }
    </Transition>
  );
};

与一位朋友反复讨论解决方案,我们找到了解决方案(大部分是他找到了诚实的解决方案)。

首先,正确数据的呈现是我的一个简单疏忽,所以我们没有直接使用来自上下文的数据,而是使用我们传递给转换的数据 API。

<p className='station-text'>{text}</p>

然后我的朋友找到了我正在寻找的“交错渲染”功能请求。 https://github.com/pmndrs/react-spring/issues/1064

所以我们专注于寻找解决方法,并意识到我们可以将数组发送到 API 中的各种动画状态。

enter={[{ display: 'none' }, { display: 'block', opacity: 1, transform: 'translate3d(0%, 0%, 0)' }]}

这解决了我的用例并回答了我的问题。 下面是一个代码块,适用于单个项目或数组项目,每当我们更新上下文数据时,将播放正确的动画,并使用新数据创建新组件,如预期的那样。

<Transition
      items={[contextData.textToRender.firstString, contextData.textToRender.secondString]}
      from={{ opacity: 0, transform: 'translate3d(0%, -15%, 0)' }}
      enter={[{ display: 'none' }, { display: 'block', opacity: 1, transform: 'translate3d(0%, 0%, 0)' }]}
      leave={[{ display: 'block', opacity: 0, transform: 'translate3d(-15%, 0%, 0)' }, { display: 'none' }]}
    >
      {(text) =>
        text &&
        ((styles) => (
          <div style={styles}>
            <p className='station-text'>{text}</p>
          </div>
        ))
      }
 </Transition>