React Junior
207 subscribers
37 photos
462 links
Изучение React с нуля
加入频道
Нашелся старый пост с субъективным сравнением разных способов стилизации React-приложений: https://yangx.top/react_junior/229

Надо признать, что с тех пор мои предпочтения немного изменились и в большинстве своих проектов я использую Styled Components. Синтаксис стал привычнее, и в целом это решение весьма удобное. НО! - только если стилей мало. Для больших простыней по-прежнему предпочитаю модули + препроцессоры.

#стили
👍2
Next.js. Страница 404

По умолчанию Next предлагает свою страницу 404 для несуществующих роутов, но мы можем ее заменить. Для этого нужно просто создать файл pages/404.tsx и вернуть из него нужный компонент.

Демо-проект: https://codesandbox.io/p/sandbox/stupefied-sutherland-r0xd40?selection=%5B%7B%22endColumn%22%3A2%2C%22endLineNumber%22%3A3%2C%22startColumn%22%3A2%2C%22startLineNumber%22%3A3%7D%5D&file=%2Fpages%2F404.tsx

#nextjs #серверныйрендеринг
👍3🔥1
Next.js. Получение данных на сервере

Переходим к самому интересному. Как сделать так, чтобы на клиент приходила страница уже с данными. Например, список постов? Нужно запросить данные еще на сервере и уже с ними отрендерить компонент, чтобы клиент получил готовый HTML.

Судя по документации у Next есть минимум три разных способа это сделать. В курсе подробно разбирается метод getInitialProps, поэтому начнем с него, хотя, кажется, что это не самый лучший подход.

Компоненту, которому нужны данные, нужно добавить статический метод getInitialProps. Сервер использует его при рендере страницы.

Метод должен вернуть объект, который будет передан в компонент как пропсы.

Получим например, список постов для страницы posts.tsx:

export default function Posts({ posts }) {
//..
}

Posts.getInitialProps = async () => {
const response = await fetch('https://jsonplaceholder.typicode.com/posts');
const posts = await response.json();

return {
posts
}
}


Работает это вполне логично:

1. Сервер получает запрос к странице Posts.
2. Видит, что у компонента этой страницы есть метод getInitialProps и выполняет его.
3. То, что получилось на выходе, передается в сам компонент в виде пропсов.
4. Компонент рендерится в HTML-код.
5. Клиент получает готовую страницу (уже с данными).

Звучит прям ну очень знакомо, да? Классический серверный рендеринг.

Проблема в том, что пока выполняется запрос, клиент ждет с пустой страницей.

#nextjs #серверныйрендеринг
🔥3👍2
Next.js. getInitialProps

Метод getInitialProps вызывает каждый раз при переходе на страницу. И при первом запросе, когда сервер рендерит нам страницу, и при каждом переходе на клиенте, в режиме SPA.

То есть, мы вводим в адресную строку урл localhost/posts - сервер выполняет запрос для получения нужных пропсов - страница загружается уже с данными.

Затем мы на клиенте переходим на главную и обратно на /posts - метод снова вызывается для получения пропсов. При этом, если метод работает долго, переход будет задерживаться.

Можно использовать такой подход:

- если метод вызывается на сервере (для первичного рендеринга приложения), то оставить все как есть
- если метод вызывается на клиенте (при переходе с другой страницы SPA), не вызывать getInitialProps. По сути мы быстро отрендерим пустой компонент (без пропсов), а уже потом (в хуке useEffect) загрузим нужные данные, показывая в это время понятный лоадер.

Звучит как дублирование логики, но ок - как нам понять, где именно вызывается метод?

getInitialProps при вызове получает один аргумент - контекст вызова. В нем куча данных, в том числе объекты req и res - HTTP-запрос и HTTP-ответ соответственно. Они приходят только если вызов произошел на сервере, то есть по их наличию можно ориентироваться.

export default function Posts({ posts }) {
const [postsList, setPostsList] = useState(posts);
useEffect(function() {
if (!posts) {
// загрузить посты на клиенте
}
})

if (!posts) {
// вернуть лоадер
}

// вернуть страницу с постами
}

Posts.getInitialProps = async ({ req }) => {
if (!req) {
return { posts: null }
}

const response = await fetch('https://jsonplaceholder.typicode.com/posts');
const posts = await response.json();

return {
posts
}
}


#nextjs #серверныйрендеринг
👍6
Next.js. getInitialProps - параметры

Тот же подход можно использовать для предварительной загрузки поста на сервере - страница post/[id]. Но тут нам нужно знать значение динамического параметра.

Получить его можно из того же объекта контекста, который передается в метод getInitialProps.

export default SinglePost({ post }) => {
// ...
};

SinglePost.getInitialProps = async ({ query }) => {
const response = await fetch(
`https://jsonplaceholder.typicode.com/posts/${query.id}`
);
const post = await response.json();
return {
post,
};
};


#nextjs #серверныйрендеринг
👍4
Next.js + TypeScript

Для описания страниц в Next-приложении нам потребуется тип NextPage (импортируется из пакета next). Это дженерик, который принимает тип пропсов компонента.

#nextjs #серверныйрендеринг #typescript
👍2🔥1
Next.js. getServerSideProps

Вероятно, вместо getInitialProps лучше использовать getServerSideProps.

Идея такая же, но getServerSideProps работает ТОЛЬКО на сервере (не запускается при переходе между страницами на клиенте в режиме SPA. То есть данные запрашиваются один раз и переиспользуются при загрузке страницы любым способом.

Разница:

- getInitialProps это статический метод компонента, а getServerSideProps просто функция, которую нужно импортировать из файла страницы.
- getServerSideProps должна вернуть объект с полем props.
- так как getServerSideProps работает только на сервере, нам не требуется проверять наличие req.

#nextjs #серверныйрендеринг
👍4🔥1
Forwarded from Cat in Web
Все виды Server-side рендеринга в NextJS: SSR, CSR, SSG, ISR

Видео (рус.): https://www.youtube.com/watch?v=xg-lajRmCco

Видео на 15 минут с обзором различных способов рендеринга в современном фронтенде. Примеры в основном на Next.js (React).

CSR - Client Side Rendering

Самая привычная нам форма работы, при которой все запросы исходят с клиента и DOM полностью формируется на клиенте.
Из минусов:
- долгая первая загрузка бандла (потом его можно закешировать), при которой пользователь видит только пустую страницу
- плохая SEO, так как поисковик тоже видит пустую страницу

SSR - Server Side Rendering

В этом подходе сервер самостоятельно рендерит страницу (при необходимости получает для нее данные) и отдает на клиент уже готовый HTML, который затем проходит гидратацию и становится нормальным SPA. Это SEO friendly, тратит меньше ресурсов устройства, но требуется время для подготовки страницы на сервере.

SSG - Static Site Generation

Другой способ - отрендерить все страницы сразу же, во время сборки проекта, не дожидаясь запросов пользователя. Готовые HTML складываются на сервере и при запросе сразу отдаются без затрат времени на подготовку. Не подходит для контента который должен быть актуальным. Также сомнительный способ, если на вашем сайте тысячи страниц (например, большой блог).

ISR - Incremental Static Regeneration

Та же SSG, но с возможностью обновить сгенерированные страницы по таймеру.

#serversiderendering #nextjs #ssr #ssg #isr
👍4
Next.js. Ошибка гидратации

Иногда выскакивает ошибка типа:

next-dev.js?3515:20 Warning: Prop `className` did not match. Server: "sc-ipEyDJ SbBBO" Client: "sc-gswNZR cjWWhU"


И в конце сообщения ссылка https://nextjs.org/docs/messages/react-hydration-error.

Это ошибка гидратации, когда на сервере рендерится одно, а при первом рендере в браузере - другое. Она может возникать, если мы используем в коде условия, которые по разному вычисляются на сервере и на клиенте. Или при невалидной HTML-разметке.

В моем случае ошибка связана с библиотекой Styled Components: рендерятся разные классы для элемента.

Чтобы такого не было, нужно правильно настроить проект. Обязательно нужно добавить файл pages/_document и плагин babel-plugin-styled-components (файл .babelrc описан здесь https://dev.to/aprietof/nextjs--styled-components-the-really-simple-guide----101c).

Для Next.js 12.1+ достаточно добавить опцию в конфиг next.config.js. Описано здесь: https://nextjs.org/docs/advanced-features/compiler#styled-components

#nextjs #серверныйрендеринг #ошибки #стили #важно
👍1🔥1
Forwarded from Cat in Web
Roadmap для React-разработчика

https://roadmap.sh/react

От базовых концепций - компонентов и хуков - до тестирования и фреймворков. Полезная штука для представления современной React-экосистемы.

#react #roadmap
👍2
С Наступающим! 🎄
Интересных проектов, профессиональных достижений и прекрасного настроения в Новом году! Ура! 🎇
👍5🎉4🍾1🎄1
Forwarded from Cat in Web
12 хуков React, которые должен знать каждый разработчик

Статья (рус.): https://nuancesprog.ru/p/16589/

В статье есть реально классные библиотеки, которые стоит взять на заметку.

1. react-swipeable - для обработки свайпов
2. use-resize-observer - позволяет изменять размеры элемента и измерять их
3. formik - для всей рутины с формами (валидация, посещенные поля и т.д.)
4. use-debounce - позволяет отслеживать какие-то изменения с задержкой для увеличения производительности
5. use-isomorphic-layout-effect - нужен для SSR, так как на сервере нельзя использовать хук useLayoutEffect
6. swr - библиотека для получения данных (stale-while-revalidate)
7. react-hotkeys-hook - для работы с горячими клавишами
8. @use-gesture/react - обработка жестов и различных событий
9. react-script-hook - для динамической загрузки внешних скриптов
10. react-scroll-parallax - для реализации параллакса при скроллинге
11. react-storage-hooks - для синхронизации состояния приложения с хранилищем (`localStorage`/`sessionStorage`)
12. @chakra-ui/color-mode - поддержка светлого и темного режимов

#react #hooks #библиотеки
👍3
Next.js. SSG

Сегодня забежим вперед и глянем одним глазом на SSG в Next.js - Static Site Generation.
Сразу предупреждаю: делается это только из неутолимого интереса и больше наощупь, чем по проверенным рецептам.

Итак, предполагается, что при сборке все странички сразу должны отрендериться с начальными данными и появиться в проекте в виде готовых HTML-документов.

Вместо getServerSideProps нужно использовать функцию getStaticProps (сигнатура у нее практически такая же).
Нужно внести изменения на страницах posts и post/[id].

С posts никаких проблем не возникло, а вот с динамическим роутом все сложнее. Там мы вытаскиваем id поста из параметра context.query, но при статической генерации никакого query у нас не будет. И как вообще понять, какие у нас есть посты и какие страницы для них генерировать?

Для этого есть еще одна функция getStaticPaths, которая как раз и должна вернуть нам все необходимые урлы. Их нужно вернуть в поле paths (массив):

export const getStaticPaths: GetStaticPaths = async function() {
const paths = [
{ id: '1' },
{ id: '2' },
{ id: '3' }
];

return {
paths,
fallback: false,
};
};


Функция асинхронная, так что внутри нее можно выполнить, например, запрос к базе данных и получить айдишники всех существующих постов.

Теперь в функцию getStaticProps нам будут приходить параметры для каждого поста. Их можно получить из поля params.

export const getStaticProps: GetStaticProps = async function(context) {
const { id } = context.params;
const response = await fetch(
`https://jsonplaceholder.typicode.com/posts/${id}`
);
const post = await response.json();
return {
props: {
post
}
}
}


Теперь запускаем команду npm run build и смотрим в папку .next/server/pages. Тут можно найти все наши странички уже в виде HTML. Кроме того, для каждой страницы генерируется еще JSON-файл с данными.

#nextjs #серверныйрендеринг #примерыкода
👍3🔥1
Next.js. API

Next позволяет легко создавать эндпоинты API.

Создаем в папке pages новую папку api, а в ней - файлы для эндпоинтов.
Из каждого файла нужно по дефолту экспортировать функцию, которая будет обрабатывать запрос.

export default function echo(req, res) {
res.status(200).json({
message: req.query.message,
});
}


Обратиться к нему можно по урлу /api/echo?message=SomeText.

В папке api также можно создавать роуты с динамической частью: pages/api/[id].ts. Динамический параметр можно получить из req.query.id.

#nextjs #серверныйрендеринг
👍3🔥2
Переходим к нашему любимому чтению документации: https://nextjs.org/docs/getting-started

В курсе есть еще несколько интересных моментов, например, работа с TypeScript, файл конфигурации и библиотека для отображения состояния загрузки при переходе между страницами, но первые два я планирую разобрать по документации, а третий пока выглядит больше как магия, нужно копнуть Next чуть глубже, чтобы понять, что там происходит.

#документация #nextjs #серверныйрендеринг
👍4
Next.js. Начало работы

Статьи в документации (англ.):
https://nextjs.org/docs/getting-started
https://nextjs.org/docs/basic-features/pages

Проще всего начать работу с помощью утилиты create-next-app (есть флаг --typescript`) , но можно и вручную все сделать. Для этого нужно к обычному React-приложению (`react, react-dom`) добавить еще пакет `next и пару npm-скриптов для запуска. Все самое приятное уже есть из коробки - сборка, запуск сервера, быстрое обновление.

У нас есть две важные папки - pages и public. Про страницы мы уже в целом знаем.

Нам снова рассказывают про SSG (Static Generation, генерация во время сборки) и SSR (Server Side Rendering), говорят, что эти подходы можно совмещать, но сильно рекомендуют SSG. Говорят, что если не получается чистый SSG, то можно сделать SSG для костяка страницы, а данные запрашивать уже на клиенте.

#документация #nextjs #серверныйрендеринг
🔥3👍1
Next.js. Data Fetching

Статьи в документации (англ.):
- https://nextjs.org/docs/basic-features/data-fetching/overview
- https://nextjs.org/docs/basic-features/data-fetching/get-server-side-props
- https://nextjs.org/docs/basic-features/data-fetching/get-static-paths
- https://nextjs.org/docs/basic-features/data-fetching/get-static-props

Чтобы заполнить наши шаблоны данными, нам необходимо эти данные получить. Делать это можно в разное время, как мы уже знаем:

- в рантайме при запросе к странице - getServerSideProps
- при сборке - getStaticProps + getStaticPaths
- на клиенте - useEffect

getServerSideProps

При каждом запросе к странице Next.js (на сервере) будет выполнять функцию getServerSideProps и рендерить компонент страницы с полученными данными. На клиенте эта функция никогда не выполняется и вырезается из клиентского бандла.
Если мы переходим на страницу с помощью next/link или next/router, функция тоже выполняется (API-запрос).

Использовать эту функцию нужно в том случае, если данные необходимо получать именно во время запроса (авторизация/гео-локация/актуальные данные).

Документация советует не использовать API-роуты (папка pages/api) внутри getServerSideProps, так как это снижает производительность. Лучше напрямую выполнять запросы из функции.

Функция имеет доступ к объекту запроса (ctx.res). Это позволяет управлять кэшем:

export async function getServerSideProps({ req, res }) {
res.setHeader(
'Cache-Control',
'public, s-maxage=10, stale-while-revalidate=59'
)

return {
props: {},
}
}

При возникновении ошибки в getServerSideProps рендерится страница 500 ошибки.

getStaticPaths

Функция необходима для динамических роутов, чтобы указать, какие значения могут принимать динамические параметры. Она возвращает объект с двумя полями paths и fallback (false/true/'blocking', разберемся с этим параметром чуть позже).

Здесь можно обратиться к базе данных/файловой системе и получить все возможные значения параметров.

Функция выполняется только при сборке и не входит в клиентскую сборку, так что здесь смело можно писать серверный код (например, обращение к БД). В режиме разработки функция выполняется при каждом запросе.

Необходимо использовать вместе с getStaticProps, так как нужно передать полученные динамические параметры на страницу.

getStaticProps

Идея та же, что и у getServerSideProps, но выполняется не в рантайме, а во время сборки. Является предпочтительным методом запроса данных.

Выполняется только на сервере, не входит в клиентскую сборку.

Документация советует не использовать API-роуты (папка pages/api) внутри getStaticProps, так как это снижает производительность. Лучше напрямую выполнять запросы из функции.

Не имеет доступа к объекту запроса.

При выполнении функции getStaticProps Next.js генерирует HTML-файл и вдобавок к нему JSON-файл, который используется, если на страницу переходят на клиенте с помощью next/link или next/router. То есть запросы заново не выполняются, берутся те данные, которые были получены при сборке.

В режиме разработки функция выполняется при каждом запросе.

#nextjs #серверныйрендеринг #документация
👍2
Next.js. Инкрементальная статическая регенерация

Если мы используем подход SSG, то для внесения любых изменений нужно пересобрать приложение (например, если появились новые посты).

Но Next позволяет избежать пересборки - этот подход называется ISR - Incremental Static Regeneration. Для его использования нужно только добавить поле revalidate в результат функции getStaticProps:

export async function getStaticProps() {
...
return {
props: {},
revalidate: 10
}
}


Значение - это количество секунд, по истечении которых нужно обновить пропсы. То есть мы делаем первый запрос, функция выполняется и результат кешируется на 10 секунд. После этого времени для нового запроса функция будет выполнена заново.

#nextjs #серверныйрендеринг #документация
👍2🔥1
Next.js. useSWR

Для запроса данных на стороне клиента нам настойчиво рекомендуют библиотеку SWR, которая предоставляет много плюшек вроде кеширования, ревалидации, перезапроса данных и т.д.

#nextjs #серверныйрендеринг #документация
👍3🔥1
Next.js. getStaticPaths - fallback

Параметр fallback определяет поведение Next.js при обращении к странице с несуществующим динамическим параметром.

fallback: false

Если fallback: false, то для неперечисленных параметров будет возвращаться страница 404. Это удобно, если у вас не очень много роутов и они не часто добавляются.

fallback: true

Если fallback: true, то при обращении к странице с несуществующим параметром будет возвращена "резервная" версия страницы.

Резервная - значит, с пустыми пропсами. При этом у объекта роутера поле isFallback будет равно true:

import { userRouter } from 'next/router';

function Post({ post }) {
const router = useRouter();

if (router.isFallback) {
// рендеринг экрана загрузки
}

// рендеринг поста
}


Резервная страница будет отображаться до тех пор, пока Next в фоновом режиме не сгенерирует HTML и JSON для новой страницы (getStaticProps). Затем браузер получит JSON и отрендерит новую страницу, а новый путь добавится в список "уже отрендеренных". По сути у нас тут SSR.

Этот подход полезен, если у вас очень много страниц, которые зависят от данных (например, товары в интернет-магазине). Если рендерить страницы для всех товаров при сборке, это займет слишком много времение, поэтому изначально рендерим лишь некоторые страницы (getStaticPaths) и включаем fallback: true.

При запросе неуказанных товаров будет выполняться getStaticProps в фоновом режиме, а пользователь будет видеть резервную версию страницы, пока она не загрузится.

fallback: 'blocking'

Если fallback: 'blocking', то будет то же самое, что и для fallback: true, но резервная страница во время загрузки отображаться не будет.

#nextjs #серверныйрендеринг #документация
👍4