我目前正在通过生命周期事件(例如class
)将应用文件从componentDidMount
更改为带有functions
钩子的useEffect
。
对于大多数文件,我没有看到任何问题,但是在下面,我遇到了性能问题,该应用程序冻结了。控制台中的错误或警告为零,但我的机器和Chrome浏览器增加了此标签上使用的内存。
我错过了什么?
基于旧类的文件代码
listener: any;
componentDidMount() {
const { firebase } = this.props;
this.listener = firebase.onAuthUserListener(
(authUser: any) => {
localStorage.setItem('authUser', JSON.stringify(authUser));
this.setState({ authUser });
},
() => {
localStorage.removeItem('authUser');
this.setState({ authUser: null });
}
);
}
componentWillUnmount() {
this.listener();
}
带有钩子的新功能(导致性能问题)
const listener = () => {
firebase.onAuthUserListener(
(authUser: any) => {
localStorage.setItem('authUser', JSON.stringify(authUser));
setState(authUser);
},
() => {
localStorage.removeItem('authUser');
setState(null);
}
);
};
useEffect(() => {
listener();
return () => {
listener();
};
});
也许值得一提的是,我将TypeScript与React结合使用。
答案 0 :(得分:2)
onAuthUserListener
返回一个要退订的函数。卸载组件时应使用此选项。
在您的代码中,您没有返回取消订阅功能。
const listener = () => {
firebase.onAuthUserListener(..) // problem here no return
}
因此,在useEffect
下,您应该正确分配它,并在useEffect
的退货中使用它。
const [user, setUser] = React.useState(null);
useEffect(
() => {
// v------ proper assignment.
const listener = firebase.onAuthUserListener(
(authUser: any) => {
localStorage.setItem('authUser', JSON.stringify(authUser));
setUser(authUser);
},
() => {
localStorage.removeItem('authUser');
setUser(null);
}
);
return () => listener();
}
, [] // no deps
);
答案 1 :(得分:1)
这可能是错误:
useEffect(() => {
listener();
return () => {
listener(); <--- here
};
});
问题是,为了触发listener();
呼叫,需要更改什么状态?
我认为:
const listener = () => {
firebase.onAuthUserListener(
(authUser: any) => {
localStorage.setItem('authUser', JSON.stringify(authUser));
setState(authUser);
},
() => {
localStorage.removeItem('authUser');
setState(null);
}
);
};
应转换为React Hook。干杯!
答案 2 :(得分:0)
useEffect
需要一个依赖项数组作为第二个参数,否则它将继续在每个渲染器上运行。由于您正在更新状态,因此会不断重复
useEffect(() => {
listener();
return () => {
listener();
};
}, []);
您可以使用Runaway Effects或ESLint之类的工具进行静态分析,以预先找出这些问题。