如何在将组件实例移动到另一个父组件时保留组件的实例?
How to preserve a component's instance while moving it to another parent component in react?
假设我们有两个名为 OldContainer
和 NewContainer
的同级 React 组件。 OldContainer
中有一个包含 <video>
标记的子组件,当前正在播放视频。
用户现在可以拖动子组件(与视频一起)并将其放在 NewContainer
中,他们希望视频在被拖动时和被放下后继续播放。
所以视频似乎固定在鼠标位置,当拖放到新容器中时,它会动画到新位置(同样,它不会暂停)。
您将如何实施?能不能用纯粹的方式实现(本着纯函数的精神)?
澄清:我本可以使用其他元素而不是视频标签来解释这个问题。 NumberEasing
元素是一个更好的例子,因为它需要在交互期间和之后保留组件的 props 和状态。
更新 1:代码示例显然会很好,但我主要寻找的只是对如何在 "functional" 方式。您如何使您的视图代码简单易懂?谁处理拖放手势?您如何对输入视图的数据建模?
您想保留什么?组件作为状态保存的是 Javascript 个对象,还是 DOM 中的状态(例如视频播放了多长时间,或输入框中的文本选择)?
如果它只是 Javascript 对象作为状态,您最好将该状态的源移动到另一个服务(例如 Flux)。这样,组件是否重新创建并不重要,因为它可以使用之前的状态重新创建。
编辑
让视图代码简单易懂的方法是不要在组件中保留状态。相反,组件需要的所有数据都应该作为 props 传递到组件中。这样,该组件是 "pure",因为它在给定相同道具的情况下呈现相同的输出。这也使得想要重用组件实例的问题不再是问题,因为相同的输入何时产生相同的输出并不重要。
对于拖放,我建议查看:https://github.com/gaearon/react-dnd。
如何对传递给视图组件的数据建模取决于您和您的应用程序的需要。组件不应该关心,它们应该只期望获取作为 props 传递的数据,并渲染它们。但是处理这个问题的流行方法当然是 Flux,并且有许多库以不同的方式实现 Flux。
第二次编辑
关于您是否有一个包含数百个要移动的组件的子树:我仍然会先将状态设为外部(纯组件),然后在新位置渲染该树。这意味着 React 可能会重新创建整个子树,这很好。我不会偏离那条道路,除非它的性能被证明是可怕的(仅仅猜测它可能是可怕的是不够的)。
如果结果证明性能很糟糕,我会将整个子树包装在一个组件中,该组件缓存实际的 DOM 树并重用它(如果它通过了相同的道具)。但是你应该只在绝对需要的时候才这样做,因为它违背了 React 试图为你做的事情。
第三次编辑
关于手势:我首先会在 componentDidMount
中监听手势事件,然后在事件回调调用 setState
中使用它应该具有的坐标对组件进行调用。然后使用给定的坐标渲染 render
中的组件。当您调用 setState
时,React 不会重新创建组件,但它会重新渲染它(并区分输出)。如果你唯一改变的是坐标,它应该渲染得足够快。
如果事实证明这太慢了,比如如果那个组件的子树很大并且它成为重新创建 vDOM 的子树的瓶颈,我会重新定位 DOM直接在 Reacts 控制之外的 RAF 循环中的节点。而且我还会对为什么需要这样做发表大量评论,因为稍后对于其他开发人员来说这可能看起来很奇怪。
使用 const
或 var
创建一个新变量。使用 rest spread 运算符放置数据实例,更新必要的数据以传递并将数据发送到组件而不改变组件的状态。
就像:
const data = {
...this.state.child,
new_data : 'abc'
}
看看这个图书馆:react-reverse-portal
假设我们有两个名为 OldContainer
和 NewContainer
的同级 React 组件。 OldContainer
中有一个包含 <video>
标记的子组件,当前正在播放视频。
用户现在可以拖动子组件(与视频一起)并将其放在 NewContainer
中,他们希望视频在被拖动时和被放下后继续播放。
所以视频似乎固定在鼠标位置,当拖放到新容器中时,它会动画到新位置(同样,它不会暂停)。
您将如何实施?能不能用纯粹的方式实现(本着纯函数的精神)?
澄清:我本可以使用其他元素而不是视频标签来解释这个问题。 NumberEasing
元素是一个更好的例子,因为它需要在交互期间和之后保留组件的 props 和状态。
更新 1:代码示例显然会很好,但我主要寻找的只是对如何在 "functional" 方式。您如何使您的视图代码简单易懂?谁处理拖放手势?您如何对输入视图的数据建模?
您想保留什么?组件作为状态保存的是 Javascript 个对象,还是 DOM 中的状态(例如视频播放了多长时间,或输入框中的文本选择)?
如果它只是 Javascript 对象作为状态,您最好将该状态的源移动到另一个服务(例如 Flux)。这样,组件是否重新创建并不重要,因为它可以使用之前的状态重新创建。
编辑
让视图代码简单易懂的方法是不要在组件中保留状态。相反,组件需要的所有数据都应该作为 props 传递到组件中。这样,该组件是 "pure",因为它在给定相同道具的情况下呈现相同的输出。这也使得想要重用组件实例的问题不再是问题,因为相同的输入何时产生相同的输出并不重要。
对于拖放,我建议查看:https://github.com/gaearon/react-dnd。
如何对传递给视图组件的数据建模取决于您和您的应用程序的需要。组件不应该关心,它们应该只期望获取作为 props 传递的数据,并渲染它们。但是处理这个问题的流行方法当然是 Flux,并且有许多库以不同的方式实现 Flux。
第二次编辑
关于您是否有一个包含数百个要移动的组件的子树:我仍然会先将状态设为外部(纯组件),然后在新位置渲染该树。这意味着 React 可能会重新创建整个子树,这很好。我不会偏离那条道路,除非它的性能被证明是可怕的(仅仅猜测它可能是可怕的是不够的)。
如果结果证明性能很糟糕,我会将整个子树包装在一个组件中,该组件缓存实际的 DOM 树并重用它(如果它通过了相同的道具)。但是你应该只在绝对需要的时候才这样做,因为它违背了 React 试图为你做的事情。
第三次编辑
关于手势:我首先会在 componentDidMount
中监听手势事件,然后在事件回调调用 setState
中使用它应该具有的坐标对组件进行调用。然后使用给定的坐标渲染 render
中的组件。当您调用 setState
时,React 不会重新创建组件,但它会重新渲染它(并区分输出)。如果你唯一改变的是坐标,它应该渲染得足够快。
如果事实证明这太慢了,比如如果那个组件的子树很大并且它成为重新创建 vDOM 的子树的瓶颈,我会重新定位 DOM直接在 Reacts 控制之外的 RAF 循环中的节点。而且我还会对为什么需要这样做发表大量评论,因为稍后对于其他开发人员来说这可能看起来很奇怪。
使用 const
或 var
创建一个新变量。使用 rest spread 运算符放置数据实例,更新必要的数据以传递并将数据发送到组件而不改变组件的状态。
就像:
const data = {
...this.state.child,
new_data : 'abc'
}
看看这个图书馆:react-reverse-portal