V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
O3Q
V2EX  ›  问与答

一个关于 MobX 的疑问,为什么没有触发重新渲染?

  •  
  •   O3Q · 2021-04-22 13:56:41 +08:00 · 1212 次点击
    这是一个创建于 1093 天前的主题,其中的信息可能已经有所发展或是发生改变。

    在学习和使用 MobX 的时候遇到了一点问题:函数组件中可以正常触发组件重渲染,但是在相同行为的类组件中无法触发重渲染。 请问大神们这是为何?

    依赖版本:

    mobx: 6.2.0

    mobx-react: 7.1.0

    react: 16.8.6

    react-dom: 16.8.6


    可复现的代码:

    import React from "react"
    import ReactDOM from "react-dom"
    import {makeAutoObservable} from "mobx";
    import { observer } from "mobx-react"
    
    class Timer {
        secondsPassed = 0
    
        constructor() {
            makeAutoObservable(this)
        }
    
        increase() {
            this.secondsPassed += 1
        }
    
        reset() {
            this.secondsPassed = 0
        }
    }
    
    const myTimer = new Timer()
    
    const TimerView = observer((props) => (
        <button onClick={() => props.timer.increase()}>Seconds passed: {props.timer.secondsPassed}</button>
    ))
    
    
    const Demo = observer(class Demo extends React.Component {
        public render = () => {
            return <button onClick={() => this.props.timer.increase()}>Seconds passed: {this.props.timer.secondsPassed}</button>
        }
    })
    
    ReactDOM.render(<>
        <Demo timer={myTimer} />
        <TimerView timer={myTimer} />
    </>, document.body)
    
    JK9993
        1
    JK9993  
       2021-04-22 14:27:03 +08:00
    请使用 state
    JK9993
        2
    JK9993  
       2021-04-22 14:28:08 +08:00
    看错了,抱歉
    lblblong
        3
    lblblong  
       2021-04-22 14:51:37 +08:00
    在类上使用是用装饰器,你这...

    ```typescript
    @observer
    class Demo extends React.Component {
    ...

    ```
    SilencerL
        4
    SilencerL  
       2021-04-22 15:01:23 +08:00
    @lblblong #3
    虽然我不知道为啥楼主在类组件里面不重新渲染
    但是目前来看装饰器不就是个语法糖……实际上用装饰器和 observer(component) 是一样的效果吧
    lblblong
        5
    lblblong  
       2021-04-22 15:50:31 +08:00
    @SilencerL 好像是这样的,见笑了

    我仔细看了下,楼主可能是类方法写错了,不能这么定义类方法吧
    public render = () => {..}
    改成 render(){} 或者 const render = () => {} 应该就可以了
    ytxbnahn
        6
    ytxbnahn  
       2021-04-22 16:03:27 +08:00
    ```
    const Demo = observer(
    class Demo extends React.Component {
    render() {
    return (
    <button onClick={() => this.props.timer.increase()}>
    Seconds passed: {this.props.timer.secondsPassed}
    </button>
    );
    }
    }
    );
    ```
    JK9993
        7
    JK9993  
       2021-04-22 16:40:38 +08:00
    用 `observer` 包装 Class Component 的时候,它会使用 `makeClassComponentObserver` 方法。该方法会修改组件的 [`render` 方法]( https://github.com/mobxjs/mobx-react/blob/baa737e4faf458e3f4c89edebacfb8774b64353d/src/observerClass.ts#L55),这样才能收集到依赖。
    而当你使用箭头函数的时候,如果你使用 `bebel` 或者其他编译器向低版本转化的话,箭头函数就会变成在构造函数中赋值的形式。
    这个时候 `makeClassComponentObserver` 取到的该组件的 `render` 属性为 undefined,这样就会收集不到依赖,因此无法更新。
    O3Q
        8
    O3Q  
    OP
       2021-04-22 16:55:12 +08:00
    @lblblong
    @ytxbnahn
    感谢二位的指点~

    @JK9993
    非常感谢这位朋友从源码 /底层的层面解答了问题~非常有帮助,感恩 2021 !
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2594 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 15:19 · PVG 23:19 · LAX 08:19 · JFK 11:19
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.