ReactJS:为啥将组件初始状态传递给一个反模式?

Posted

技术标签:

【中文标题】ReactJS:为啥将组件初始状态传递给一个反模式?【英文标题】:ReactJS: Why is passing the component initial state a prop an anti-pattern?ReactJS:为什么将组件初始状态传递给一个反模式? 【发布时间】:2015-05-01 08:20:48 【问题描述】:

我在 SocketIO 的帮助下创建了一个小型 ReactJS 仪表板,用于实时更新。即使我更新了仪表板,但我不确定我是否正确地更新了它。

最让我烦恼的是Props in getInitialState as anti-pattern 的帖子。我创建了一个仪表板,可以从服务器获取实时更新,除了加载页面之外不需要用户交互。根据我的阅读,this.state 应该包含决定是否应该重新渲染组件的内容,而this.props....我还不知道。

但是,当您最初调用React.render(<MyComponent />, ...) 时,您只能传递道具。就我而言,我从服务器获取所有数据,所以初始道具最终还是以this.state 结尾。所以我所有的组件都有这样的东西:

getInitialState: function() 
    return 
        progress: this.props.progress,
        latest_update: this.props.latest_update,
        nearest_center: this.props.nearest_center
    

除非我误解了上述博客文章,否则这是一种反模式。但是我看不到将状态注入组件的其他方法,我不明白为什么它是一种反模式,除非我重新标记所有道具以在它们前面加上 initial。如果有的话,我觉得这是一种反模式,因为现在我必须跟踪比以前更多的变量(那些以initial 开头的变量和那些没有的变量)。

【问题讨论】:

2017 年,Facebook 在其文档中演示了使用道具设置初始状态:reactjs.org/docs/react-component.html#constructor @Rohmer 的链接包含指向You probably don't need derived state 的链接,其中深入讨论了替代方案以及应避免的事项。 【参考方案1】:

免责声明:当我回答这个问题时,我正在学习/尝试 实施 vanilla Flux,我对此有点怀疑。后来我 将所有内容迁移到 Redux。所以,一个建议:只要使用 Redux 或 MobX。你可能甚至不需要这个问题的答案 不再是(科学除外)。

将初始状态作为prop 传递给组件是一种反模式,因为getInitialState 方法仅在组件第一次呈现时被调用。这意味着,如果您将 不同 值作为 prop 重新渲染该组件,该组件将不会做出相应的反应,因为该组件将保持第一次渲染时的状态。这很容易出错。

这是你应该做的:

尽量让你的组件无状态。无状态组件更容易测试,因为它们基于 输入 呈现 输出。就这么简单。

但是嘿..我的组件数据改变了..我不能让它们无状态

是的,对于大多数人来说,你可以。为此,请选择一个外部组件作为状态持有者。使用您的示例,您可以创建一个包含数据的 Dashboard 组件和一个完全无状态的 Widget 组件。 Dashboard 负责获取所有数据,然后渲染多个Widgets,它们通过props 接收所需的一切。

但是我的小部件有一些状态.. 用户可以配置它们。如何使它们无国籍?

您的Widget 可以公开事件,这些事件在处理时会导致Dashboard 中包含的状态发生变化,从而导致每个Widget 都被重新呈现。通过让props 接收函数,您可以在Widget 中创建“事件”。

好的,现在,Dashboard 保持状态,但我如何将初始状态传递给它?

你有两个选择。最推荐的方法是在 Dashboard getInitialState 方法中进行 Ajax 调用,以从服务器获取初始状态。您还可以使用Flux,这是一种更复杂的数据管理方式。 Flux 更像是一种模式,而不是一种实现。您可以将纯 Flux 与 Facebook 的 Dispatcher 实现一起使用,但您可以使用第三方实现,例如 Redux、Alt 或 Fluxxor。

或者,您可以将此初始状态作为prop 传递给Dashboard,明确声明这只是初始状态.. 例如initialData。但是,如果您选择此路径,则不能将不同的初始状态传递给它,因为它会“记住”第一次渲染后的状态。

OBS

你的定义不太对。

State 用于存储可变数据,即在组件生命周期中会发生变化的数据。状态的改变应该通过setState 方法进行,并且会导致组件重新渲染。

Props 用于将不可变数据传递给组件。它们不应在组件生命周期内更改。只使用 props 的组件是无状态的。

This 是“如何将初始状态传递给组件”的相关来源。

【讨论】:

它描述得很好,但是......一如既往地是一个“但是”。如果我有一个组件,它获取图像数组并创建带有缩略图和 onlick 事件的子组件,这应该改变这个组件中的大图像。图像未处于状态,因此我无法使用其他组件来维护它。图像是本地的,我需要一些本地状态来管理哪些应该显示为大图像。我很想在 state 中使用 props,但是会收到警告:setState(...): Cannot update during an existing state transition(例如在render 内)。渲染方法应该是 props 和 state 的纯函数。 那么,对于使用componentWillReceiveProps(nextProps) 设置状态有什么意见吗? componentWillRecieveProps() 自 16.3 起已弃用,所以...不。不要使用它。 @Alejandro - You probably don't need derived state 是对使用(已弃用)componentWillReceiveProps 或其(未弃用)替换 getDerivedStateFromProps 的缺陷的深入解释。底线:文章展示了几种替代解决方案,调用其中任何一种方法,并解释了为什么要使用这些替代方法。

以上是关于ReactJS:为啥将组件初始状态传递给一个反模式?的主要内容,如果未能解决你的问题,请参考以下文章

Reactjs、父组件、状态和道具

ReactJS:如何将子组件传递给它的祖先?

如何在 ReactJS 中将更改的状态从子组件传递给其父组件

JSON对象与窗口变量,用于使用reactjs传递服务器端呈现的初始状态

Reactjs - 将状态值从一个组件传递到另一个组件

ReactJS - 如何将组件引用作为道具传递给另一个组件?