
Привет, разработчики React и энтузиасты JavaScript!
Вы когда-нибудь хотели добавить раздел комментариев на свой веб-сайт или в приложение, чтобы повысить вовлеченность пользователей и поощрить обсуждения? Ну, не смотрите дальше! В этой статье мы проведем вас через пошаговое руководство о том, как реализовать полнофункциональный раздел комментариев с помощью платформы React Server. React Server позволяет создавать серверные приложения с модульной структурой, управляемой компонентами, точно так же, как React используется во внешнем интерфейсе. К концу этого руководства вы получите более глубокое представление о React Server и сможете создать свой собственный раздел комментариев, что сделает ваш веб-сайт или приложение еще более интерактивным и привлекательным. Итак, давайте погрузимся и начнем!
Посетите документацию и примеры на https://state-less.cloud

Предпосылки
Прежде чем мы начнем, убедитесь, что на вашем локальном компьютере установлено следующее:
- Node.js (версия 16 или выше)
- npm (версия 6 или выше)
Настройка нового проекта
Запустите сервер
git clone https://github.com/state-less/clean-starter.git -b react-server comment-app-backend cd comment-app-backend git remote remove origin yarn install yarn start
Запустите клиент
Создайте новый проект vite и выберите React в качестве фреймворка и TypeScript в качестве варианта.
yarn create vite comment-app-frontend
Теперь перейдите во вновь созданную папку, установите зависимости и добавьте @apollo/client и state-less/react-client в свой проект и запустите сервер.
cd todo-app-frontend yarn yarn add @mui/material @mui/icons-material yarn add @emotion/react @emotion/styled yarn add @apollo/client state-less/react-client yarn dev
Создание экземпляра клиента GraphQl
Чтобы подключиться к нашему бэкенду, нам нужно создать клиент GraphQl. Создайте новый файл под comment-app-frontend/src/lib/client.ts и вставьте следующее содержимое.
import { ApolloClient, InMemoryCache, split, HttpLink } from "@apollo/client";
import { WebSocketLink } from "@apollo/client/link/ws";
import { getMainDefinition } from "@apollo/client/utilities";// Create an HTTP link
const localHttp = new HttpLink({
uri: "http://localhost:4000/graphql",
});
// Create a WebSocket link
const localWs = new WebSocketLink({
uri: `ws://localhost:4000/graphql`,
options: {
reconnect: true,
},
});
// Use the split function to direct traffic between the two links
const local = split(
({ query }) => {
const definition = getMainDefinition(query);
return (
definition.kind === "OperationDefinition" &&
definition.operation === "subscription"
);
},
localWs,
localHttp
);
// Create the Apollo Client instance
export const localClient = new ApolloClient({
link: local,
cache: new InMemoryCache(),
});
export default localClient;
Это устанавливает новый клиент GraphQl с подписками, которые будут использоваться клиентом React Server. Подписки необходимы для того, чтобы сделать ваше приложение реактивным.
Примечание. Сейчас вам нужно создать этот файл вручную, но позже он будет создан с помощью инициализатора или react-client, который предоставит способ загрузить клиент graphql, предоставив URL-адрес, указывающий на сервер реагирования. Сейчас вам нужно вручную создать и предоставить клиент GraphQl.
Бэкэнд
На данный момент вы можете отложить любые опасения по поводу кода. Все, что вам нужно сделать, это запустить сервер, и пример сервера автоматически будет обслуживать компонент комментариев.
Откройте файл по адресу comment-app-backend\src\lib\permissions.ts и укажите свой адрес электронной почты в качестве администратора. Мы будем использовать это позже, чтобы аутентифицировать вас и разрешить вам удалять другие комментарии.
export const admins = ['[email protected]'];
Фронтенд
Чтобы потреблять и взаимодействовать с компонентом комментариев, вам нужно использовать компонент, используя хук useComponent, предоставленный @state-less/react-client.
Создайте файл в папке todo-app-frontend\src\components\Comments.tsx и вставьте следующее содержимое.
import {
Alert,
Avatar,
Button,
Card,
CardActions,
CardContent,
Chip,
IconButton,
TextField,
Tooltip,
Typography,
} from '@mui/material';
import { authContext, useComponent } from '@state-less/react-client';
import { useContext, useState } from 'react';
import GoogleIcon from '@mui/icons-material/Google';
import DeleteIcon from '@mui/icons-material/Delete';
export const Comments = ({ id = 'comments' }) => {
const [component, { error, loading }] = useComponent(id, {});
const [comment, setComment] = useState('');
const comments = component?.props?.comments || [];
const canComment = component?.props?.permissions.comment;
const canDelete = component?.props?.permissions.delete;
return (
<Card>
{loading && <Alert severity="info">Loading...</Alert>}
{error && <Alert severity="error">{error.message}</Alert>}
{!canComment && (
<Alert severity="info">You need to be logged in to comment.</Alert>
)}
{comments.map((comment, index) => {
return (
<Comment
comment={comment}
del={() => component?.props?.del(index)}
canDelete={canDelete}
/>
);
})}
<CardContent>
<TextField
multiline
rows={3}
onChange={(e) => setComment(e.target.value)}
fullWidth
value={comment}
/>
</CardContent>
<CardActions>
<Tooltip
title={canComment ? '' : 'You need to be logged in to comment.'}
>
<span>
<Button
onClick={() => {
component?.props?.comment(comment);
setComment('');
}}
disabled={!canComment}
>
Add
</Button>
</span>
</Tooltip>
</CardActions>
</Card>
);
};
const StrategyIcons = {
google: GoogleIcon,
};
const Comment = ({ comment, del, canDelete }) => {
const { session } = useContext(authContext);
const isOwnComment =
comment.identity.email === session?.strategies?.[session.strategy]?.email ||
(comment.identity.strategy === 'anonymous' &&
comment.identity.id === JSON.parse(localStorage.id));
const Icon = StrategyIcons[comment.strategy];
return (
<Card sx={{ m: 1 }}>
<CardContent sx={{ display: 'flex' }}>
<Typography variant="body1">{comment.message}</Typography>
</CardContent>
<CardActions>
{(canDelete || isOwnComment) && (
<IconButton onClick={del}>
<DeleteIcon />
</IconButton>
)}
<Chip
avatar={
comment.identity.picture && (
<Avatar src={comment.identity.picture}>
<Icon />
</Avatar>
)
}
label={comment.identity.name}
sx={{ ml: 'auto' }}
></Chip>
</CardActions>
</Card>
);
};
Замените содержимое todo-app-frontend\src\App.tsx
import { ApolloProvider } from '@apollo/client'
import './App.css'
import { Comments } from './components/Comments'
import localClient from './lib/client'
function App() {
return (
<div className="App">
<ApolloProvider client={localClient}>
<Comments />
</ApolloProvider>
</div>
)
}
export default App
Теперь удалите весь код из comment-app-frontend/src/index.css.
Запустите интерфейс с yarn dev и посетите http://127.0.0.1:5173/. Вы должны увидеть пустой раздел комментариев, который в настоящее время не позволяет вам добавлять комментарии.
Чтобы добавлять комментарии, вам нужно либо отключить аутентификацию на сервере, либо, что лучше, реализовать аутентификацию на своем сайте.
Реализация аутентификации
Процесс прост с реагирующим сервером.
Сначала установите react-google-login yarn add react-google-login и создайте новый файл в разделе comment-app-frontend/src/components/GoogleButton.tsx.
import { Avatar, Button } from '@mui/material';
import { authContext } from '@state-less/react-client';
import { useContext } from 'react';
import GoogleLogin from 'react-google-login';
import GoogleIcon from '@mui/icons-material/Google';
const logError = (response) => {
console.log(response);
};
export const LoggedInGoogleButton = (props) => {
const { session, authenticate } = useContext(authContext);
if (session.strategy !== 'google') {
return null;
}
const decoded = session.strategies.google.decoded;
return (
<Button color="secondary">
<Avatar
src={decoded.picture}
sx={{ width: 24, height: 24, mr: 1 }}
></Avatar>
{decoded.name}
</Button>
);
};
export const GoogleLoginButton = () => {
const { session, authenticate } = useContext(authContext);
return session?.strategy === 'google' ? (
<LoggedInGoogleButton />
) : (
<GoogleLogin
clientId="534678949355-odq15l4236372p864f63ci14g794sfqf.apps.googleusercontent.com"
buttonText="Login"
onSuccess={({ accessToken, tokenId }) => {
console.log('Authenticating with google');
authenticate({
strategy: 'google',
data: { accessToken, idToken: tokenId },
});
}}
render={(props) => {
return (
<Button color="secondary" {...props}>
<GoogleIcon sx={{ mr: 1 }} />
Login
</Button>
);
}}
onFailure={logError}
cookiePolicy={'single_host_origin'}
/>
);
};
Теперь обновите файл comment-app-frontent/src/App.tsx и добавьте GoogleLoginButton. Не забудьте обернуть ваше приложение в AuthProvider, что необходимо для работы аутентификации.
import { ApolloProvider } from '@apollo/client'
import './App.css'
import { Comments } from './components/Comments'
import localClient from './lib/client'
import { AppBar, Paper, Toolbar } from '@mui/material'
import { GoogleLoginButton } from './components/GoogleButton'
import { AuthProvider } from '@state-less/react-client';
function App() {
return (
<div className="App">
<ApolloProvider client={localClient}>
<AuthProvider >
<AppBar>
<Toolbar>
<GoogleLoginButton />
</Toolbar>
</AppBar>
<Paper sx={{mt: 9}}>
<Comments />
</Paper>
</AuthProvider >
</ApolloProvider>
</div>
)
}
export default App

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