Доброго времени суток! Здесь вы сможете ознакомится с переводом серии статей Rahul Sharma, в которой вы найдете способы, и примеры к ним, уменьшения Вашего кода на React.
Всего в данной серии 3 статьи:
Лучшие подходы и решения для уменьшения кода на React. Часть 1
Лучшие подходы и решения для уменьшения кода на React. Часть 2
Лучшие подходы и решения для уменьшения кода на React. Часть 3
Введение
Я работаю с React последние несколько лет и использовал его в нескольких проектах. При работе на разных проектах я выделил простые паттерны, с которыми и хочу поделиться в данных статьях. Но хватит лишних слов, давайте приступать.
1. Создавайте собственные хуки для Redux
Я не фанат использования redux, но использовал библиотеку в нескольких проектов. А redux-thunk и вовсе использовался почти во всех проектах, над которыми работал. Я обнаружил, что использование данного кода довольно-таки универсально.
const useUser = () => {
const dispatch = useDispatch();
const state = useSelector(); // получение данных авторизации, как пример
const fetchUser = (id) => {
return fetch(`/api/user/${id}`).then((res) => res.json())
.then((user) => dispatch({type: "FETCH_USER", payload: user}));
};
const fetchUsers = () => {
return fetch('/api/users').then((res) => res.json())
.then((user) => dispatch({type: "FETCH_USERS", payload: user}));
};
return { fetchUser, fetchUsers };
}
Внутри компонента
const { fetchUser } = useUser();
useEffect(() => fetchUser(1), []);
Примечание: как вы можете заметить, нет необходимости создавать много функций для обработки всех redux экшенов.
Мы можем также использовать useSelector хук для получения любой информации из redux.
2. Используйте объект вместо switch внутри reducer
Плохая идея, если вы хотите использовать много switch ключей для обработки. Вы можете использовать объекты как альтернатива для switch. Это улучшит читаемость и упростит поддержку.
const actionMap = {
INCREMENT: (state, act) => ({...state, count: state.count + 1 }),
DECREMENT: (state, act) => ({...state, count: state.count - 1 }),
}
const reducer = (state, action) => {
const handler = actionMap[action.type];
return handler ? handler(state, action) : state;
};
Примечание: переменная с ключами должна быть объявлена отдельно, иначе она будет постоянно перевызываться. Сложность поиска switch O (log n), у map (объект) же O (1).
3. Создайте хук для REST запросов.
Вы можете использовать браузерное fetch API и создать собственный хук для избегания повтора кода. К примеру, получение данных из API для обновления состояния приложения и отрисовки.
const useFetch = (input, { auto, ...init }) => {
const [result, setResult] = useState([null, null, true]);
const fetcher = useCallback(
(query, config) =>
fetch(query, config)
.then((res) => res.json())
.then((data) => setResult([null, data, false]))
.catch((err) => setResult([err, null, false])),
[input, init]
);
useEffect(() => {
if (auto) fetcher(input, init);
}, []); // Если необходимо получить данные только один раз, делайте так
return [...result, fetcher];
//fetcher(refetch) это либо функция либо может быть использованно для отправки запросов
};
Внутри компонента
const Users = () => {
const [err, users, loading, refetch] = useFetch(`/api/users`, {auto:true});
const onClick = () => refetch(...);
return (
<div>
{users.map((user) => <User key={user.id} user={user} />)}
</div>
);
}
Примечание: это похоже на react-query/useSWR, и обе библиотеки могут предложить гораздо больше функционала. Вы можете использовать их, но, если есть ограничения в вашем проекте, вы можете использовать данный код как альтернативу.
4. Разделение кода
Используйте React.lazy, это мощный инструмент, который позволяет загружать ваши компоненты, только когда они необходимы. React.lazy функция дает возможность отображать динамически импортированные компоненты, как обычные.
Хорошее место для начала, это роутер. При обычном решении, перед тем как отобразить элементы на странице, вам приходится загружать все компоненты сразу, что является не хорошим решением, так как это занимает дополнительное время. Даже, когда у нас нет необходимости показывать часть из компонентов.
Мы можем использовать react.lazy для загрузки компонентов асинхронно. Так, когда вы на первой (Home) странице, вы загружаете только домашнюю страницу. А когда переходите на вторую страницу (About), подгружается второй компонент. Это решение позволяет избежать ненужные загрузки.
const Home = React.lazy(() => import('./Home'));
const About = React.lazy(() => import('./About'));
function MyComponent() {
return (
<Suspense fallback={<div>Loading...</div>}>
<Route path="/home" component={Home} />
<Route path="/about" component={About} />
</Suspense>
);
}
Примечание: это простой пример, но что будет, когда у вас будут сотни элементов навигации и компонентов? Вы увидите большое различие в производительности.
Спасибо за прочтение!
Комментарии (7)
Black_and_green
28.03.2022 09:38+1Что автор статьи, что переводчик совсем забыли, что на дворе 2022 и существует redux-toolkit, который позволяет не писать ничего из этого. А также библиотеки для работы с запросами - redux-toolkit/query и react query. Зачем нам в сотый раз создавать useFetch?
Doberman2029 Автор
28.03.2022 09:47Добрый день, спасибо за комментарий, про redux-toolkit не знал, изучу вопрос. На счет query в примечании к 3 пункту он указан, а также что в нём больше функционала. useFetch же нужен, если по каким-либо причинам на Вашем проекте не допускается добавление новых библиотек (хоть у меня так проблем не встречалось, возможно у автора статьи были).
sinneren
28.03.2022 10:04а где в первом примере используется state? К чему было подключение useSelector?
Doberman2029 Автор
28.03.2022 11:51В примере state нигде не используется, он просто указан, что так можно использовать. В рабочих же задачах без него, зачастую, не обойтись.
JustDont
0. Если вам реально надо меньше кода — не применяйте редакс и вообще забудьте его как страшный сон. Все другие стейт-менеджеры (включая и vanilla react) дадут меньше кода по объему. Подавляющее большинство других решений — будет так же и более удобно в поддержке.