【问题标题】:React not rerendering after mobx observer change在 mobx 观察者更改后反应不重新渲染
【发布时间】:2023-04-02 19:06:01
【问题描述】:

页面加载后,我看到“hi2” 当我单击按钮时,什么也没有发生。我也试过setUser

我怀疑我只是在编辑道具本身,而 observable 没有被触发?

查看它在全新的 rails/react 环境中不起作用的示例代码:https://github.com/bufordtaylor/mobxtest

  1. 克隆
  2. 捆绑
  3. 导轨 s
  4. (在另一个进程中)./bin/webpack-dev-server --host 127.0.0.1
  5. 导航到 localhost:3000

=======================

更新:

我已将其简化为基本形式,消除了可能的导入错误、提供程序错误或构造函数错误。

在这里

import React from 'react'
import ReactDOM from 'react-dom'
import { observable, action, computed } from 'mobx';
import { Provider, inject, observer } from 'mobx-react';


class UserStore {

  @action setUser(val) {
    console.log(val);
    this.user = val;
  }

  @observable user = "default";
}

const userStore = new UserStore();

@observer
class Hello extends React.Component {
  render() {
    return (
      <div>
        hi2 {this.props.userStore.user}
        <button onClick={this.props.userStore.setUser.bind(this,"fwefwe")}>faew</button>
      </div>
    )
  }
}

document.addEventListener('DOMContentLoaded', () => {
  ReactDOM.render(
    <Hello userStore={userStore} />,
    document.getElementById('app'),
  )
})

【问题讨论】:

  • It works for me。你能弄清楚你的情况有什么不同吗?
  • 不走运。我将您的代码直接复制到我的编辑器中。 @Tholle。
  • 这很烦人。我看到的唯一看起来有点可疑的是import UserStore from '../bundles/User/stores/UserStore';../bundles/User/stores/UserStore 是预期的导入吗?
  • 无赖。可以尝试将transform-decorators-legacy 放在 babel 插件列表的首位吗?
  • 我为这个问题发疯了。从昨天下午 4 点开始,我就在笔记本电脑前弯腰驼背,几乎没有睡觉,喝了太多咖啡,对我的妻子大发雷霆,最后……我有了一个决心。谢谢@Tholle!

标签: reactjs mobx mobx-react


【解决方案1】:

我的问题是包装组件的顺序,因为我使用的是 Material UI 框架。

错误

export inject('store')(observer(withStyles(styles)(MyComponent)));

正确

export withStyles(styles)(inject('store')(observer(MyComponent)));

所以,MobXReact Material UI 的顺序很重要。

【讨论】:

  • 你救了我的命
  • @ArjunTRAj 也许是别的东西在搞乱 Mobx。尝试仅在组件上使用注入和观察者,看看是否是问题所在。否则,它可能会有所不同。我发现除非您从组件中的商店读取,否则不会触发渲染。
【解决方案2】:

如果你使用最新版本的 mobx,以及 babel 7.12 版本 将此添加到您的构造函数中

makeObservable(this)

【讨论】:

  • 谢谢。这个对我有用。但是你有一个错字。应该是makeObservable(this)
  • 很高兴找到这个答案,谢谢!
  • 是否有其他人遇到过在本地环境中观察到商店但在生产环境中观察不到的错误?通过将观察者附加到子组件来解决此问题,但我不确定这是否旨在以这种方式工作。
  • 这成功了!但是,为什么 @observer 装饰器不再起作用?它甚至没有给出警告......(版本:mobx@6.3.2,mobx-react@7.2.0 - 我注意到@observer 装饰器在今天从 mobx 5 更新到 6 后不再工作)
  • 好的,我找到了答案:mobx.js.org/enabling-decorators.html 问题不是@observer 类装饰器,而是@observable field 装饰器——字段-装饰器现在需要在构造函数中调用才能“应用”。 (详情见上面的链接)
【解决方案3】:

您的代码看起来不错。我认为您偶然发现了文档的How to (not) use decorators 部分中讨论的问题。 transform-decorators-legacy 在 babel 插件列表中排在第一位很重要。

【讨论】:

  • 我最近在使用 parcel-bundler 时遇到了这个问题。这是因为 parcel 中似乎存在一个错误,无法正确解析 tsconfig.json 文件。见here
【解决方案4】:

对于到达这里的任何人,请确保您不是像我这样的彻头彻尾的白痴,并且您没有忘记在类组件之前添加 @observer 装饰器。

(或者商店里的@observable装饰器)

天哪,浪费了一整天的时间

【讨论】:

  • 你不是一个人,我也忘了用观察者函数包装我的函数组件。 10K+ 声望...没什么意义:)
【解决方案5】:
<button onClick={this.props.userStore.setUser.bind(this,"fwefwe")}>faew</button>

小心。您正在绑定this。在这种情况下,This 是 Hello 组件的实例。现在 setUser 函数中的 this 指向 Hello 组件。所以 setUser 会在 Hello 组件中设置一个属性 user。

 @action setUser(val) {
    console.log(val);
    this.user = val; // This this now points to the Hello Component.
  }

要理解我的意思,您可以在 setUser 方法上设置断点,然后检查变量 this。您会看到它指向 Hello 组件,而不是您的 stores 实例。

改为执行以下操作:

<button onClick={() => { this.props.userStore.setUser("fwefwe"); }}>faew</button>

在这里,我正在创建一个在用户存储上调用 setUser 的 lambda。 因为我这里使用的是 lambda,所以 this.props.userStore 中的 this 指向 Hello 组件。

【讨论】:

    【解决方案6】:

    我有类似的问题,我使用箭头函数作为渲染方法:

    render = (): React.ReactNode
    

    正确的应该是:

    render(): React.ReactNode
    

    仍然不确定为什么第一种情况会混淆 mobx。

    【讨论】:

      【解决方案7】:

      我确信发生这种情况的原因有很多。

      就我而言,我没有使用装饰器。我只是在我的 mobx 状态对象的构造函数中使用了makeAutoObservable(this)。我的组件没有在状态更改时重新渲染的原因是因为我没有对 state 属性应用默认值。

      我有一个这样定义的属性:

      showModalForIssue: IssueTreeNode;
      

      我有一个 observer 组件正在使用此属性,但在更改它的值时没有重新渲染。

      经过一番讨论后,我最终通过简单地在其定义中应用一个默认值(将其设置为null)来修复它,如下所示:

      showModalForIssue: IssueTreeNode = null;
      

      这一定与makeAutoObservable(this) 的工作方式有关。

      【讨论】:

        【解决方案8】:

        在我的例子中,在运行旧版本的 mobx (4.3) 时,问题来自一个组件,该组件呈现另一个组件并将 lambda 传递给返回节点的组件

        @observer
        class Parent extends Component {
          @observable
          value = "Initial";
        
          renderSub() {
            return <Text>{this.value}</Text>
          }
        
          render() {
            return <Child primary={() => this.renderSub()} onPress={() => (this.value = "Other")} />;
          }
        }
        
        class Child extens Component {
          render() {
            return this.props.primary();
          }
        }
        

        这会破坏。解决方法是直接传递节点:

        class Parent extends Component {
          render() {
            return <Child primary={this.renderSub()} />;
          }
        }
        

        这可能是因为渲染发生在不同的组件中,因为 lambda 超出了父组件的更改跟踪,另一个可能的修复可能是使子组件也成为 @observer,但是我更喜欢我的修复,所以我没有尝试过

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-03-19
          • 2019-08-09
          • 1970-01-01
          • 2017-08-24
          • 1970-01-01
          • 2020-08-24
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多