Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mobx推荐不使用setState是在讲什么 #10

Open
gzqby opened this issue Jun 3, 2021 · 0 comments
Open

mobx推荐不使用setState是在讲什么 #10

gzqby opened this issue Jun 3, 2021 · 0 comments

Comments

@gzqby
Copy link
Owner

gzqby commented Jun 3, 2021

文章流程是这样的:首先是题目与几个观点,然后通过几个问题讲一讲mobx的逻辑,然后再回到题目的观点,最后就是对mobx或者其他方案的态度就是没态度。或者说团队开发是软工的事,个人就随心意

mobx推荐不使用setstate是在说什么

题目的来源是在读mobx文档时看到的,即以上链接,给出的几个观点

  1. setState is asynchronous
  2. setState causes unnecessary renders
  3. setState is not sufficient to capture all component state

通过几个问题来理解mobx的逻辑

  1. how can let React render?how can let react escape rerender?

    • there are useState, setState and force-update

      // 一种渲染和规避的方式
      class Demo extends React.Component{
        state = {
          box: 1
        }
      
        shouldComponentUpdate(_, state) {
          // console.log(arguments);
          return state.box>5 ? false : true;
        }
      
        render() {
          return <div>
            <h1>hello world, {this.state.box}</h1>
            <button onClick={()=>this.setState(prevState=>({
              box: prevState.box+1
            }))}>click+</button>
          </div>
        }
      }
      
  2. how MOBX render?

    const box = observable.box(1);
    const act = action(()=>{
      box.set(box.get()+1)
    })
    autorun(()=>{
      console.log(box.get());
    })
    
    act()
    act()
    act()
    act()
    
  3. what does the inject of Mobx-react do?

    基本主要就是做了把context作为props传递给组件

    function createStoreInjector(
        grabStoresFn: IStoresToProps,
        component: IReactComponent<any>,
        injectNames: string,
        makeReactive: boolean
    ): IReactComponent<any> {
        // Support forward refs
        let Injector: IReactComponent<any> = React.forwardRef((props, ref) => {
            const newProps = { ...props }
            const context = React.useContext(MobXProviderContext)
            Object.assign(newProps, grabStoresFn(context || {}, newProps) || {})
    
            if (ref) {
                newProps.ref = ref
            }
    
            return React.createElement(component, newProps)
        })
    
        if (makeReactive) Injector = observer(Injector)
        Injector["isMobxInjector"] = true // assigned late to suppress observer warning
    
        // Static fields from component should be visible on the generated Injector
        copyStaticProperties(component, Injector)
        Injector["wrappedComponent"] = component
        Injector.displayName = getInjectName(component, injectNames)
        return Injector
    }
    
  4. what does the observe of Mobx-react do?

    重要的,首先是Reaction对象,去track(利用getter把reaction传递给observable,最后addObserver)

    trackDerivedFunction<T>(derivation: IDerivation, f: () => T, context: any) {
        const prevAllowStateReads = allowStateReadsStart(true)
        // pre allocate array allocation + room for variation in deps
        // array will be trimmed by bindDependencies
        changeDependenciesStateTo0(derivation)
        derivation.newObserving_ = new Array(derivation.observing_.length + 100)
        derivation.unboundDepsCount_ = 0
        derivation.runId_ = ++globalState.runId
        const prevTracking = globalState.trackingDerivation
        globalState.trackingDerivation = derivation
        globalState.inBatch++
        let result
        if (globalState.disableErrorBoundaries === true) {
            result = f.call(context)
        } else {
            try {
                // 这里通过globalState同步关联
                result = f.call(context)
            } catch (e) {
                result = new CaughtException(e)
            }
        }
        globalState.inBatch--
        globalState.trackingDerivation = prevTracking
        // 这个地方是把Reaction 绑定到observable
        bindDependencies(derivation)
    
        warnAboutDerivationWithoutDependencies(derivation)
        allowStateReadsEnd(prevAllowStateReads)
        return result
    }
    
    const reaction = new Reaction(`${initialName}.render()`, () => {
            if (!isRenderingPending) {
                // N.B. Getting here *before mounting* means that a component constructor has side effects (see the relevant test in misc.js)
                // This unidiomatic React usage but React will correctly warn about this so we continue as usual
                // See #85 / Pull #44
                isRenderingPending = true
                if (this[mobxIsUnmounted] !== true) {
                    let hasError = true
                    try {
                        setHiddenProp(this, isForcingUpdateKey, true)
                        if (!this[skipRenderKey]) Component.prototype.forceUpdate.call(this)
                        hasError = false
                    } finally {
                        setHiddenProp(this, isForcingUpdateKey, false)
                        if (hasError) reaction.dispose()
                    }
                }
            }
        })
    
  5. why it doesn't re-render when i update simple context object, and it does when i update MOBX object?

    • 其实不是observable有什么想不到的东西,还是在数据变动,去触发react更新。
    const aaa = {
      box: 1,
      plus() {
        this.box++;
      },
    }
    
    const ctx = React.createContext(aaa)
    
    const MMMM = () => {
      const ctxx = React.useContext(ctx);
      const [_, setA] = React.useState(0);
      return <div>
        <h1>hello mobx, {ctxx.box}</h1>
        <button onClick={()=>{
          // act();
          ctxx.plus();
          console.log(ctxx.box, aaa.box);
          if(ctxx.box > 5) {
            setA(ctxx.box)
          }
        }}>
        click+
      </button></div>
    }
    

针对问题的思考

  1. 我的理解是这样的,数据和状态是分离的,所以能保持数据同步!
  2. 处理不必要渲染是这样的?针对class组件是使用shouldComponentUpdate!(函数组件暂未详细看)
  3. state当然不能管理所有的组件状态?一个对象就能管理即observable对象

总结

同步是否易于开发?(就是个个人感知问题!)是不是最优解哪?hooks能不能解决上述问题

我的总结没有答案。我想说的是:基于一点点的不同,一点点的变化,一点点的用户习惯,造轮子有没有必要?前端生态的繁荣有时候就是靠这些一点点,才有我们今天应对各种场景时,选择方案的从容。

so保持开放的心态,持续学习

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant