假设我们有两个兄弟反应组分OldContainer
和NewContainer
。OldContainer
内部有一个子组件,包含<video>
标签,并且视频当前正在播放。
用户现在可以拖动子组件(与视频)并将其放到NewContainer
中,并且他们希望视频在被拖动和被放置后继续播放。
所以视频看起来会固定在鼠标的位置,当在新容器中拖放时,它会移动到它的新位置(同样,它不会暂停)。
你将如何实现这个?我们能以一种纯粹的方式(符合纯函数的精神)实现这一点吗?
说明:我本可以使用其他元素而不是视频标签来解释这个问题。NumberEasing
元素是一个更好的例子,因为它需要在交互期间和之后保留组件的道具和状态。
Update 1:代码示例显然会很好,但我主要寻找的只是如何以"功能"方式处理此问题的一般描述。如何保持视图代码简单且易于推理?谁处理拖放手势?如何对输入视图的数据进行建模?
看看这个库:
你想要保存的是什么?是Javascript对象作为组件的状态,还是DOM中的状态(比如视频播放了多长时间,或者输入框中的文本选择)?
如果它只是Javascript对象作为状态,你最好将该状态的源移动到另一个服务(如Flux)。这样,即使组件被重新创建也没关系,因为它可以用之前的状态被重新创建。
编辑
保持视图代码简单和易于推理的方法是不要在组件中保留状态。相反,组件需要的所有数据都应该以props的形式传递给组件。这样,组件是"纯"的,因为它在给定相同的道具时呈现相同的输出。这也使得想要重用组件实例的问题不存在,因为当相同的输入给出相同的输出时,这并不重要。
对于拖放,我建议查看:https://github.com/gaearon/react-dnd.
如何对传递给视图组件的数据建模取决于您和应用程序的需要。组件不应该关心这些,它们只应该期望获得作为道具传递的数据,并渲染它们。但是处理这个问题的流行方法当然是Flux,并且有许多库以不同的方式实现了Flux。第二个编辑
如果你有一个包含数百个组件的子树,你想要移动:我仍然会从外部状态(纯组件)开始,并在一个新的地方渲染该树。这意味着React可能会重新创建整个子树,这很好。我不会偏离这条道路,除非它的性能被证明是糟糕的(仅仅猜测它可能是糟糕的是不够的)。
如果结果证明性能很糟糕,我会将整个子树包装在一个组件中,该组件缓存实际的DOM树并重用它(如果传递的是相同的道具)。但是你应该只在绝对需要的时候才这样做,因为它违背了React试图为你做的事情。
第三编辑关于手势:我开始监听手势事件在componentDidMount
,并在事件回调调用setState
上的组件与坐标它应该有。然后用给定的坐标在render
中渲染组件。当你调用setState
时,React不会重新创建组件,但它会重新渲染它(并对输出进行差分)。如果你唯一改变的是坐标,它应该渲染得足够快。
如果结果是太慢,就像如果组件的子树是巨大的,它成为一个瓶颈,重新创建vDOM的子树,我将直接在反应控制之外的raf循环中重新定位DOM节点。我还对为什么需要这样做做了大量的评论,因为这对其他开发人员来说可能会很奇怪。
使用const
或var
创建一个新变量。把数据的实例使用rest扩展操作符,更新必要的数据传递和发送到组件,而不改变组件的状态。
就像:
const data = {
...this.state.child,
new_data : 'abc'
}