Javascript useEffect与redux道具更新
我有一个可以在一个页面上多次使用的组件。它所做的是进行一个外部调用,并将该外部调用中的值保存到键对象中的redux存储。我只希望组件执行一次,所以我使用的是componentDidMount。现在,如果在页面上再次使用相同的组件,我不希望它再次执行外部调用。这在使用类时可以正常工作,但当我尝试使用函数挂钩时,它就不再工作了。 让我首先向您展示基于类的代码Javascript useEffect与redux道具更新,javascript,reactjs,Javascript,Reactjs,我有一个可以在一个页面上多次使用的组件。它所做的是进行一个外部调用,并将该外部调用中的值保存到键对象中的redux存储。我只希望组件执行一次,所以我使用的是componentDidMount。现在,如果在页面上再次使用相同的组件,我不希望它再次执行外部调用。这在使用类时可以正常工作,但当我尝试使用函数挂钩时,它就不再工作了。 让我首先向您展示基于类的代码 class MyComponent extends Component { componentDidMount() { setTi
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);
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]==未定义。第二个组件挂载映射[key]不再是未定义的。但是如果没有超时映射,[key]总是===未定义
它将传递的密钥属性存储在redux中。第二个组件装载并看到存储了相同的密钥,因此它不需要再次调用外部API getExternalID。如果第三个组件安装了不同的密钥,那么它应该再次运行外部API调用,依此类推
正如我所说的,以上所有方法都有效,但我不确定为什么我需要做一个设置来让它工作
第二个问题是将其转换为函数和挂钩,而不是类。由于某些原因,这不起作用
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;
第一个问题:
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();
但这是一个有点糟糕的分享参考。因此,更好的设计可能是使用缓存。不要通过地图,而是一个能手和一个二传手。getKey和saveKey。这些方法的底层可能会使用映射来持久化已设置的键。谢谢semako。我认为componentDidMount是React,意思是“React的渲染方法exit”与React的第一次渲染相同,您可以安全地使用dom或其他任何东西。在我的例子中,您的组件呈现为调用外部api。第二个问题。saveKey是一个动作,您可以从我的代码中看到这一点。导出默认ConnectMapStateTops,{saveKey,setValue}MyComponent;map是redux store的道具,从mapStateToProps获取。这就是我在开场白中提到的对象键。它是Redux中存储密钥的对象。可以在我的Reducer代码中看到。是的,componentDidMount是调用外部API的好地方。但是,如果您在设置的超时时间内执行此操作,则会发生与react lifecycle不同步的情况。在这种情况下,最好的办法可能是从组件中删除API调用,并将其放入一个缩减器中。。。
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();
if (map[key] === undefined) {
map[key]=true;
saveKey(key);
console.log('LOAD VARIANT ONLY ONCE');
externalAPI(externalHandler);
}