Короткие и полезные заметки про React
export const getUser = builder.createRequest<UserModel>()({
endpoint: "/api/user/:userId",
cache: true,
cacheTime: DateInterval.second * 10
});
export const postFile = builder
.createRequest<{ response: string }, { file: File }>()({
endpoint: "/api/files",
method: "POST",
queued: true,
retry: 0
})
.setDataMapper((data) => {
try {
const formData = new FormData();
formData.append("file", data.file);
return formData;
} catch (err) {
return data;
}
});
https://hyperfetch.bettertyped.com/
const {pending, data, action, method} = useFormStatus();
Его можно использовать для отображения индикатора загрузки. Хук сделан на основе хука useTransition. Для реализации внутри используется startTransition и объект контекста.
https://github.com/facebook/react/pull/26722null | JSX.Element. Однако, в React компоненты могут возвращать ReactNode. Этот тип включает в себя number | string | Iterable<ReactNode> | undefined и также в будущем будет включать Promise<ReactNode>.
Таким образом, при обновлении на TypeScript 5.1+ открываются следующие возможности:
- использование асинхронных серверных компонентов.
- в функциях компонента возвращать значение из списка ReactNode без использования Fragment.
- другие возможности, такие как зеркальный курсор для редактирования JSX тега в VSCode и использование атрибутов JSX с пространством имен.
devblogs.microsoft.com/typescr…5-1-beta
const getInitialState = () => Number(window.localStorage.getItem('count'))
const [count, setCount] = React.useState(getInitialState)
julesblom.com/writing…rameters
function Counter() {
const [count, setCount] = useState(0);
const increment = () => {
setCount(count + 1);
console.log(count); // 0
};
}
Однако, значение стейта обновится только при следующем рендере. Следовательно, нет смысла сразу читать значение стейта после установки. Для решения проблемы можно использовать useEffect.
claritydev.net/blog/th…ng-react
// page.loader.ts
export type ProfileData = {
/* some types */
};
export default async (): Promise<ProfileData> => {
const res = await fetch('https://api/user/profile');
return await res.json();
};
// page.tsx
import { useLoaderData } from '@modern-js/runtime/router';
import type { ProfileData } from './page.loader.ts';
export default function UserPage() {
const profileData = useLoaderData() as ProfileData;
return <div>{profileData}</div>;
}
Другие возможности:
- Создание BFF. Для этого нужно добавить BFF плагин в конфиг, и можно определять свои функции в папке /api.
- Кастомизация веб-сервера. Можно добавить обработку аутентификации пользователя, пререндеринг скелетона приложения и т.д.
- Встроенная поддержка микро-фронтенда. Через конфиг можно настроить работу нескольких фронтенд приложений.
- Есть встроенный стейт-менеджер – Reduck, созданный на основе Redux.
Помимо фреймворка в экосистеме есть Modern.js Module и Modern.js Doc. Это инструменты для создания npm пакетов и фреймворк для создания документов соответственно.
https://modernjs.dev/en
function groupBy(rows, columnId) {
const groupMap = new Map<any, Row<TData>[]>()
return rows.reduce((map, row) => {
const resKey = `${row.getValue(columnId)}`
const previous = map.get(resKey)
if (!previous) {
map.set(resKey, [row])
} else {
map.set(resKey, [...previous, row])
}
return map
}, groupMap)
}
Здесь использовался спред оператор […previous, row] для конкатенации текущей строки в конец массива. Так как он использовался внутри другого цикла reduce, то сложность функции группировки была O(n^2). Поэтому для 50к строк выполнялось 2,5 миллиарда итераций.
jpcamara.com/2023/03…ble.html@preact/signals-react.
Пример использования:
export function Counter() {
const [count, setCount] = createSignal(0);
return <button onClick={() => setCount(count() + 1)}>{count()}</button>
}
www.lksh.dev/blog/wr…-library