重构Logout组件为函数组件:useEffect依赖[login]是否必要?
问题背景与代码
我正在把旧的React类组件转成函数组件,碰到一个别人写的logout类组件,代码如下:
import React from 'react'; import { Text, } from 'react-native'; import { connect } from 'react-redux'; import { deauthenticateUser } from '../state/actions'; class LogoutScreen extends React.Component { constructor() { super(); } async shouldComponentUpdate(nextProps, nextState) { if(nextState.login == false) { this.props.deauthenticateUser(); this.props.navigation.navigate('Auth'); } return false; } componentDidMount() { this.setState({login:false}) } render() { return ( <Text>Logging out...</Text> ) } } // Redux Mapping const mapStateToProps = state => { return { ...state.User } }; const mapDispatchToProps = dispatch => ({ deauthenticateUser: user => dispatch(deauthenticateUser(user)), }); export default connect(mapStateToProps, mapDispatchToProps)(LogoutScreen);
我已经把它重构为函数组件:
import React, { useEffect, useState } from 'react'; import { Text, } from 'react-native'; import { connect } from 'react-redux'; import { deauthenticateUser } from '../state/actions'; export const LogoutScreen = (props) => { const [login, setLogin] = useState(false); useEffect(() => { if (login === false) { props.deauthenticateUser(); props.navigation.navigate('Auth'); } }, [login]); return ( <Text>Logging out...</Text> ) } // Redux Mapping const mapStateToProps = state => { return { ...state.User } }; const mapDispatchToProps = dispatch => ({ deauthenticateUser: user => dispatch(deauthenticateUser(user)), }); export default connect(mapStateToProps, mapDispatchToProps)(LogoutScreen);
提问
在此场景下,useEffect()钩子中的依赖项[login]是否有用/必要?若不包含它,组件行为会有何不同?
回答
直接说结论:这个[login]依赖项完全没必要,甚至连login这个状态都可以删掉,代码能简化不少。
为啥这个依赖没用?
你定义的login初始值就是false,而且整个组件里根本没改过它的值(连setLogin都没调用过)。所以login从始至终都是false,不会有任何变化。
加[login]依赖的话,useEffect只会在组件挂载时执行一次(因为login初始是false,之后也不变)。但就算把依赖改成空数组[],效果也是一样的——都是组件挂载时执行一次登出逻辑。
去掉依赖项会咋样?
如果完全删掉依赖数组(写成useEffect(() => {...})),那这个useEffect会在组件每次渲染时都跑一遍。你的组件本来没什么会触发重渲染的变量,但如果props里的User状态在登出后发生变化,可能会触发组件重渲染,这时候就会重复调用deauthenticateUser和导航方法,不仅做了无用功,甚至可能导致导航逻辑出问题(比如重复跳转)。
更清爽的写法
其实这个login状态纯粹是多余的,直接在组件挂载时执行登出逻辑就行:
export const LogoutScreen = (props) => { useEffect(() => { props.deauthenticateUser(); props.navigation.navigate('Auth'); }, [props.deauthenticateUser, props.navigation]); return ( <Text>Logging out...</Text> ) }
这里把props.deauthenticateUser和props.navigation加到依赖里,一是为了过React的lint检查,二是确保如果这两个props真的变化时,逻辑能正确执行(不过在这个场景里,这俩一般不会变)。
内容的提问来源于stack exchange,提问作者Muirik

