Фон
После выпуска 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: Функциональный компонент с крючками
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: Компонент, обернутый HO C
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
Но пока я нажимаю кнопку «Toggle», состояние меняется, и вот результат:
Случай 1: Функциональный компонент с хуками
render Login Screen
Button render
Button render
Случай 2: Компонент, обернутый HO C
render Login Screen
Вопросы
Хотя компонент Button не представляет собой большой набор кодов, учитывая время повторного рендеринга между двумя случаями, Case 2
должен иметь лучшую производительность, чем Case 1
. Однако, учитывая читаемость кода, я определенно люблю использовать хуки больше, чем использовать HO C. (Особенно функции: appUser.login()
и login()
)
Итак, вот вопрос. Есть ли какое-нибудь решение, в котором я могу сохранить преимущества обоих размеров, уменьшив время повторного рендеринга при использовании хуков? Спасибо.