【发布时间】:2020-09-12 18:30:15
【问题描述】:
背景
在释放React v16.8 之后,现在我们可以在 React Native 中使用钩子了。
我正在做一些简单的测试来查看渲染时间和性能
挂钩的功能组件和类组件。这是我的示例:
@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 更好。
但是,考虑到代码的可读性,我绝对喜欢使用钩子而不是使用 HOC。 (特别是函数:appUser.login()和login())
所以问题来了。有没有什么解决方案可以保持两种尺寸的好处,减少使用钩子时的重新渲染时间?谢谢。
【问题讨论】:
标签: reactjs react-native react-hooks react-context