Как лучше организовать взаимодействие между компонентами с использованием Next.JS и серверных компонентов, учитывая SSR? Например, у меня есть структура:
```jsx
<Things>
<ThingsList/>
<ThingDetails/>
<Things/>
```
В `ThingsList` у меня есть список "штучек", и при выборе одной из них в `ThingDetails` отображается их содержимое для просмотра и редактирования. В обычном React я бы вынес состояния в компоненте `Things` и перехватил бы базовую загрузку данных из базы данных, а затем передал бы ID выбранной "штучки" и другую необходимую информацию через пропсы.
```jsx
<Things>
<ThingsList items={things} onSelect={setSelectedThingID}/>
<ThingDetails item={things.get(selectedThingID} onSubmit={onThingDetailsSubmit}/>
<Things/>
```
Однако в Next серверные компоненты не могут использовать хуки и должны быть stateless. Записывать `useClient` повсюду означает, фактически, отказаться от преимуществ Next.JS. Я не понимаю, как это сделать без этого (потому что я малоопытный :)).
Какая считается наилучшей практикой в таких случаях? Как правильно организовать загрузку и передачу данных в этом контексте?
В Next.js есть несколько способов сохранить состояние и загрузить данные.
1. Сохранение состояния на сервере: Вы можете использовать серверный кэш, такой как Redis или Memcached, чтобы сохранить состояние между запросами. Вы можете использовать `getServerSideProps` в Next.js для загрузки данных из кэша и передачи их в компоненты через пропсы.
```jsx
export async function getServerSideProps() {
// Загрузка данных из кэша
const data = await cache.get('data');
return {
props: {
data
}
}
}
```
2. Сохранение состояния на клиенте: Вы можете использовать состояние компонентов вместе с `useEffect` и `useState` для сохранения состояния на клиенте. Вы можете загрузить данные с помощью Ajax или другого метода и сохранить их в состоянии.
```jsx
export default function Things() {
const [data, setData] = useState([]);
useEffect(() => {
// Загрузка данных
fetchData().then((response) => {
setData(response.data);
});
}, []);
return (
<>
<ThingsList items={data} onSelect={setSelectedThingID} />
<ThingDetails item={findSelectedThing(data, selectedThingID)} onSubmit={onThingDetailsSubmit} />
</>
);
}
```
3. Использование серверных компонентов: В более новых версиях Next.js появились серверные компоненты, которые предоставляют возможность организовать хранение состояния на сервере без применения хуков. Вы можете использовать `getServerSideProps` для загрузки данных и передачи их в серверные компоненты.
```jsx
export async function getServerSideProps() {
// Загрузка данных
const response = await fetchData();
return {
props: {
data: response.data
}
}
}
export default function Things({ data }) {
return (
<>
<ThingsList items={data} onSelect={setSelectedThingID} />
<ThingDetails item={findSelectedThing(data, selectedThingID)} onSubmit={onThingDetailsSubmit} />
</>
);
}
```
Организация взаимодействия между компонентами в Next.js следует аналогичным подходам, как и в обычном React. Вы можете передавать пропсы между компонентами, используя иерархию компонентов или с помощью "контекстной" передачи данных.
```jsx
<Things>
<ThingsList items={data} onSelect={setSelectedThingID} />
<ThingDetails item={findSelectedThing(data, selectedThingID)} onSubmit={onThingDetailsSubmit} />
</Things>
```
Общая практика состоит в том, чтобы организовывать серверные запросы и загрузку данных в верхнеуровневых компонентах и передавать данные с помощью пропсов или контекста на более низкоуровневые компоненты.
1. Можно использовать состояние общего доступа, такое как Redux. 2. Можно использовать контекст. 3. Можно изменять URL и извлекать выбранный деталь из параметра. 4. Можно разместить элементы на отдельных страницах. Лично я предпочитаю использовать четвертый вариант. Он проще и логичнее. При обновлении страницы просмотр выбранного элемента не сбрасывается. То же самое можно сказать и о третьем варианте. Одна из плюсов четвертого варианта заключается в том, что вы разделяете свой код на отдельные блоки. При сборке вашего кода бандлы будут иметь меньший объем. Если же вы размещаете все на одной странице, это приведет к созданию одного большого файла. Чтобы использовать хуки и колбэки в Next.js 13, вам просто нужно вынести часть кода, в которой используются хуки, в отдельный компонент и пометить его как "useClient". Это позволит выполнять весь код на сервере, за исключением небольшого фрагмента, который будет выполняться на клиенте. Например, я выношу только кнопку, по которой нужно осуществить подписку при клике. Все остальное будет выполняться на сервере.