gpt4 book ai didi

reactjs - React Native - 在使用 React 钩子(Hook)时减少渲染时间以优化性能

转载 作者:行者123 更新时间:2023-12-03 23:47:09 25 4
gpt4 key购买 nike

背景

发布后React v16.8 ,现在我们有了在 React Native 中使用的钩子(Hook)。
我正在做一些简单的测试来查看渲染时间和性能
Hook 的功能组件和类组件。这是我的示例:

@Components/Button.js

import React, { memo } from 'react';
import { TouchableOpacity, Text } from 'react-native';

const Button = memo(({ title, onPress }) => {
console.log("Button render"); // check render times
return (
<TouchableOpacity onPress={onPress} disabled={disabled}>
<Text>{title}</Text>
</TouchableOpacity>
);
});

export default Button;

@Contexts/User.js
import React, { createContext, useState } from 'react';
import User from '@Models/User';

export const UserContext = createContext({});
export const UserContextProvider = ({ children }) => {
let [ user, setUser ] = useState(null);

const login = (loginUser) => {
if (loginUser instanceof User) { setUser(loginUser); }
};

const logout = () => {
setUser(null);
};

return (
<UserContext.Provider value={{value: user, login: login, logout: logout}}>
{children}
</UserContext.Provider>
);
};

export function withUserContext(Component) {
return function UserContextComponent(props) {
return (
<UserContext.Consumer>
{(contexts) => <Component {...props} {...contexts} />}
</UserContext.Consumer>
);
}
}

案例

我们有以下两种情况来构建屏幕组件:

@Screens/Login.js

案例 1:带有 Hooks 的功能组件
import React, { memo, useContext, useState } from 'react';
import { View, Text } from 'react-native';

import Button from '@Components/Button';
import { UserContext } from '@Contexts/User';

const LoginScreen = memo(({ navigation }) => {
const appUser = useContext(UserContext);
const [foo, setFoo] = useState(false);

const userLogin = async () => {
let response = await fetch('blahblahblah');
if (response.is_success) {
appUser.login(user);
} else {
// fail on login, error handling
}
};

const toggleFoo = () => {
setFoo(!foo);
console.log("current foo", foo);
};

console.log("render Login Screen"); // check render times
return (
<View>
<Text>Login Screen</Text>
<Button onPress={userLogin} title="Login" />
<Button onPress={toggleFoo} title="Toggle Foo" />
</View>
);
});

export default LoginScreen;

案例 2:使用 HOC 包裹的组件
import React, { Component } from 'react';
import { View, Text } from 'react-native';

import Button from '@Components/Button';
import { withUserContext } from '@Contexts/User';
import UserService from '@Services/User';

class LoginScreen extends Component {
state = { foo: false };

userLogin = async () => {
let response = await UserService.login();
if (response.is_success) {
login(user); // function from UserContext
} else {
// fail on login, error handling
}
};

toggleFoo = () => {
const { foo } = this.state;
this.setState({ foo: !foo });
console.log("current foo", foo);
};

render() {
console.log("render Login Screen"); // check render times
return (
<View>
<Text>Login Screen</Text>
<Button onPress={userLogin} title="Login" />
<Button onPress={toggleDisable} title="Toggle" />
</View>
);
}
}

结果

两种情况在开始时具有相同的渲染时间:
render Login Screen
Button render
Button render

但是当我按下“切换”按钮时,状态发生了变化,结果如下:

案例 1:带有 Hooks 的功能组件
render Login Screen
Button render
Button render

案例 2:使用 HOC 包裹的组件
render Login Screen

问题

虽然按钮组件不是一大堆代码,但考虑到两种情况之间的重新渲染时间, Case 2应该比 Case 1 有更好的性能.
然而,考虑到代码的可读性,我绝对喜欢使用钩子(Hook)而不是使用 HOC。 (特别是函数: appUser.login()login() )

所以这就是问题所在。有没有什么解决方案可以保持两种尺寸的好处,减少使用钩子(Hook)时的重新渲染时间?谢谢你。

最佳答案

原因在于每当组件重新渲染时,新的 userLogin 就在功能组件中已创建 => Button组件被重新渲染。

const userLogin = async () => {
const response = await fetch("blahblahblah")
if (response.is_success) {
appUser.login(user)
} else {
// fail on login, error handling
}
}

您可以使用 useCallback 内存 userLogin函数 + 换行 Button React.memo 的组件(就像你所做的那样)防止不需要的重新渲染:
const userLogin = useCallback(async () => {
const response = await fetch("blahblahblah")
if (response.is_success) {
appUser.login(user)
} else {
// fail on login, error handling
}
}, [])

在类组件中没有发生的原因是类组件仅重新渲染 render函数是触发器(当然还有一些其他生命周期函数,例如 shoudlComponentUpdate、componentDidUpdate 触发器)。 ==> userLogin不变 ==> Button组件不会重新渲染。

这是 great article看看 useCallback + memo
注意:当您使用 Context , memo无法阻止的组件,这是一个 Consumer , 如果 Context Provider 的值发生变化,则重新渲染。
例如:
如果您调用 setUserUserContext => UserContext重新渲染 => value={{value: user, login: login, logout: logout}}改变 => LoginScreen重新渲染。您不能使用 shouldComponentUpdate (类组件)或 memo (功能组件)以防止重新渲染,因为它不是通过 props 更新的,它是通过 Context Provide 的值更新的

关于reactjs - React Native - 在使用 React 钩子(Hook)时减少渲染时间以优化性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62013923/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com