我们先来假设一种场景:当进入页面时需要去请求获取初始数据,初始数据中有一个字段A,当A====true时需要弹出一个弹窗。

先封装一个弹窗组件,组件接口两个参数visible、close,visible控制是否显示弹窗,close用来关闭弹窗

import React from 'react';
import styles from './index.module.scss';

interface IProps {
  visible: boolean;
  close: () => void;
}


const Popup = (props: IProps) => {

  const { visible, close } = props;

  return (
    visible ? 
    <div className={styles.container}>
      <div className={styles.box}>
        <p>确定要删除吗?</p>
        <div>
          <button onClick={close}>取消</button>
          <button>确认</button>
        </div>
      </div>
    </div>
    :
    <></>
  )
}

export default Popup;

然后在页面中调用

import { inject, observer } from 'mobx-react';
import React, { useEffect } from 'react';
import Store from '../stores/Store';
import Popup from './Popup';

interface IProps {
  store?: Store;
}

const Main = (props: IProps) => {

  const { store } = props;

  const { visible, setVisible } = store as Store;
  
  // 在dom挂在后執行
  useEffect(() => {
    setVisible(true) // 模拟请求,弹出弹窗
  })

  return <div>
    <Popup visible={visible} close={() => setVisible(false)}></Popup>
  </div>
}

export default inject('store')(observer(Main));

这里使用mobx@1.15.4,mobx-react@6.2.2,mobx6版本写法有变动

import { action, observable } from "mobx";

class Store {
  @observable visible = true;

  @action
  setVisible = (visible: boolean) => {
      this.visible = visible;
  }
}

export default Store;

当运行项目时,会发现每次点击关闭弹窗,弹窗又立即重新弹出。这是因为点击关闭时store中的visible发生变化,导致只要类组件render方法或者函数组件return中使用到visible的组件都会重新渲染,重新渲染又会触发useEffect hooks发送请求,如此循环,使得出现上述现象。

那么如何解决上述问题呢?

如果能不触发useEffect hooks是不是可以解决呢?不在外部传入visible以及close,而是在popup组件内部依赖store获取visible和close,这样父组件Main就不用重新渲染,进而useEffect hooks也不用再次执行。

将popup组件实现方式改成如下:

import React from 'react';
import { inject, observer } from 'mobx-react';
import styles from './index.module.scss';
import Store from '../../stores/Store';

interface IProps {
  store: Store;
}


const Popup = (props: IProps) => {
  const { store } = props;
  const { visible, close } = store as Store;

  return (
    visible ? 
    <div className={styles.container}>
      <div className={styles.box}>
        <p>确定要删除吗?</p>
        <div>
          <button onClick={close}>取消</button>
          <button>确认</button>
        </div>
      </div>
    </div>
    :
    <></>
  )
}

export default inject('store')(observer(Popup));

记得要微笑
1.9k 声望4.5k 粉丝

知不足而奋进,望远山而前行,卯足劲,不减热爱。