useEffect与Redux道具更新

时间:2019-04-20 18:23:28

标签: javascript reactjs

我有一个组件,可以在页面上多次使用。它的作用是进行外部调用,并将该外部调用中的值保存到键对象中的redux存储中。我只希望组件执行一次此操作,因此我正在使用componentDidMount。现在,如果同一组件再次在页面上使用,我不希望它再次执行外部调用。这在使用类时可以正常使用,但是当我尝试使用函数挂钩时,它将不再起作用。 让我开始向您展示基于类的代码。

class MyComponent extends Component {
  componentDidMount() {
    setTimeout(() => this.wait(), 0);
  }

  wait() {
    const { key, map } = this.props;
    if (map[key] === undefined) {
      saveKey(key);
      console.log('LOAD EXTERNAL ID ONLY ONCE');
      externalAPI(this.externalHandler.bind(this));
    }
  }

  externalHandler(value) {
    const { key, setValue } = this.props;
    setValue(key, value);
  }

  render() {
    const { key, map children } = this.props;
    return (
      <>
        {children}
      </>
    );
  }
} 

mapStateToProps .....

export default connect(mapStateToProps, { saveKey, setValue })(MyComponent);

Reducer.js

export default (state = {}, action = null) => {
  switch (action.type) {
    case SAVE_KEY: {
      return {
        ...state,
        [action.id]: 'default',
      };
    }

    case SET_VALUE: {
      const { id, value } = action;
      return {
        ...state,
        [id]: value,
      };
    }

    default: return state;
  }
};

Page.js 如下调用每个组件。

import React from 'react';

const Page = () => {
  return (
    <>
      <MyComponent key='xxxxx'>First Component</MyComponent>
      <MyComponent key='xxxxx'>Second Component</MyComponent>
    </>
  );
};

export default Page;

以上所有作品。因此,当第一个组件挂载时,我延迟了对redux的调用,不确定为什么会起作用,但确实可以。有人可以告诉我为什么使用setTimeout有效吗???而没有使用setTimeout则不会。通过工作,我的意思是超时,因为map [key] === undefined,第一个组件安装了set key。第二个组件挂载map [key]不再是未定义的。但是没有超时map [key]总是=== undefined吗?

它将通过的密钥prop存储在redux中。第二个组件将挂载并看到存储了相同的密钥,因此它无需再次调用外部API getExternalID。如果第三个组件安装了其他密钥,则应再次运行外部API调用,依此类推。

正如我所说的,以上所有工作均有效,但我不确定为什么需要执行setTimout才能使其正常工作。

第二个问题,将其转换为函数并进行钩子而不是类。由于某些原因,这不起作用。

import React, { useEffect } from 'react';

const MyComponent = ({ children, key, map, saveKey, setValue }) => {

  useEffect(() => {
    setTimeout(() => delay(), 0);
  }, [map[key]]);

  const delay = () => {
    if (map[key] === undefined) {
      saveKey(key);
      console.log('LOAD VARIANT ONLY ONCE');
      externalAPI(externalHandler);
    }
  };

  const externalHandler = (value) => {
    setValue(key, value);
  };


  return (
      <>
        {children}
      </>
  );
};

export default MyComponent;

1 个答案:

答案 0 :(得分:0)

第一个问题:

JavaScript使用单个线程工作,因此即使您使用延迟0毫秒,该方法也会在React的render方法退出后被调用。我相信这是一个实验,对此可以进行解释:

function log(msg){
   $("#output").append("<br/>"+msg);
}
function render(){
  log("In render");
  log("Delayed by 0 ms without setTimeout...")
  setTimeout(() =>log("Delayed by 0 ms with setTimeout..."), 0);
  for(var i = 0;i<10;i++) log("Delay inside render "+i);
  log("Render finish");
}
render();

https://jsfiddle.net/hqbj5xdr/

因此,实际上所有组件在开始检查map [key]是否未定义之前都会渲染一次。

第二个问题:

在您的示例中,并不清楚map和saveKey的来源。以及组件之间如何共享地图...

无论如何,天真的解决方案是直接更新地图。并确保所有组件 引用此地图实例(不是副本)。

if (map[key] === undefined) {
      map[key]=true;
      saveKey(key);
      console.log('LOAD VARIANT ONLY ONCE');
      externalAPI(externalHandler);
    }

但这有点不好(共享参考)。因此,更好的设计可能是使用缓存。不要传递地图,而是传递获取器和传递器。 getKey和saveKey。这些方法的基础可能是使用地图来保留已设置的键。