Автор Анна Евкова
Преподаватель который помогает студентам и школьникам в учёбе.

Знакомство и выбор технологии для разработки

Содержание:

ВВЕДЕНИЕ

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

На сегодняшний день любой человек, у которого есть компьютер, может загрузить с его помощью новости, иллюстрации, видео - или аудиоинформацию по любой интересующей его теме. Он может получать эту информацию тогда, когда он этого пожелает.

Блог - веб-сайт, основное содержимое которого - регулярно добавляемые записи, содержащие текст, изображения или мультимедиа. Для блогов характерны недлинные записи вре́менной значимости, отсортированные в обратном хронологическом порядке (последняя запись сверху).

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

Преимущества создания интернет блога:

  • Саморазвитие. Хороший способ научиться созданию сайтов;
  • Заработок. Возможна монетизация в последствии(к примеру добавление рекламы);
  • Самовыражение. Любой человек может зайти и высказаться или поделиться чем либо;

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

Целью работы является формирование теоритических знаний по проектированию web-сайта и практических навыков по его разработке.

Задачи:

  1. Проанализировать существующий стеки технологий и выбрать оптимальный
  2. Разработать макет(дизайн) сайта
  3. Наполнить сайт контентом

ТЕОРЕТИЧЕСКАЯ ЧАСТЬ

ЗНАКОМСТВО И ВЫБОР ТЕХНОЛОГИИ ДЛЯ РАЗРАБОТКИ

На первом этапе проектирования web-сайта необходимо выполнить анализ и определиться со стеком технологий.

Прежде всего следует упомянуть язык разметки гипертекстовых страниц(HTML) - представляет собой язык, разработанный специально для создания Web-документов. Он определяет синтаксис и размещение специальных инструкций (тегов), которые не выводятся на экран, но указывают браузеру, как отображать содержимое документа. Он также используется для создания ссылок на другие документы, локальные или сетевые, например, находящиеся в сети Интернет.

Стандарт HTML и другие стандарты для Web разработаны под руководством консорциума W3C (World Wide Web Consortium). Стандарты, спецификации и проекты новых предложений можно найти на сайте. На практике на стандарт HTML большое влияние оказывает наличие тегов, предложенных и поддерживаемых наиболее известными браузерами, такими как Microsoft Internet Explorer и Netscape Navigator. Эти теги в данный момент могут, как входить, так и не входить в состав действующей спецификации HTML.

Дело в том, что с HTML не представляется возможным сделать какую либо логику на сайте, на помощь приходит JavaScript - мультипарадигменный язык программирования. Так же дело в том, что создание сайтов в текущих реалиях усложнилось в разы и люди стали создавать фрейморки и библиотеки дабы упростить весь этот процесс. Если посмотреть что популярно и часто используется сейчас, то это большая тройка:

  • Angular
  • React
  • Vue

Коротко о каждом.

Angular - среда JavaScript MVVM, основанная в 2009 году, которая отлично подходит для создания интерактивных веб-приложений.

Преимущества Angular:

  • Angular используется вместе с Typescript(нужен для типизации). Он имеет исключительную поддержку для этого.
  • Angular-language-service — обеспечивает интеллектуальные возможности и автозаполнение шаблона HTML-компонента.
  • Новые функции, такие как generation Angular, использующие библиотеки npm из CLI, generation, и разработка компонентов, использующая Angular.
  • Подробная документация, позволяющая разработчику получить всю необходимую информацию, не прибегая к помощи его коллег. Однако это требует больше времени для обучения.
  • Односторонняя привязка данных, которая обеспечивает исключительное поведение приложения, что сводит к минимуму риск возможных ошибок.
  • MVVM (Model-View-ViewModel), которая позволяет разработчикам работать отдельно над одним и тем же разделом приложения, используя один и тот же набор данных.
  • Внедрение зависимостей от компонентов, связанных с модулями и модульностью в целом.
  • Структура и архитектура, специально созданные для большой масштабируемости проекта.

Недостатки:

  • Разнообразие различных структур (Injectables, Components, Pipes, Modules и т. д.) усложняет изучение по сравнению с React и Vue.js, у которых есть только «Component».
  • Относительно медленная производительность, учитывая различные показатели. С другой стороны, это можно легко решить, используя так называемый «ChangeDetectionStrategy», который помогает вручную контролировать процесс рендеринга компонентов.

Плюсы и минусы React

React — это библиотека JavaScript, разработанная Facebook в 2013 году, которая отлично подходит для создания современных одностраничных приложений любого размера и масштаба.

Преимущества React:

  • Легко изучить, благодаря простому дизайну, использованию JSX (HTML-подобный синтаксис) для шаблонов и очень подробной документации. Разработчики тратят больше времени на написание современного JavaScript и меньше беспокоятся о коде, специфичном для фреймворка.
  • Очень быстрая, благодаря реализации React Virtual DOM и различным оптимизациям рендеринга.
  • Отличная поддержка рендеринга на стороне сервера, что делает его мощной платформой для контент-ориентированных приложений.
  • Первоклассная поддержка Progressive Web App (PWA) благодаря генератору приложений `create-react-app`.
  • Привязка данных является односторонней, что означает меньше нежелательных побочных эффектов.
  • Redux, самая популярная платформа для управления состоянием приложений в React, ее легко учить и использовать.
  • React реализует концепции функционального программирования (FP), создавая простой в тестировании и многократно используемый код.
  • Приложения могут быть созданы с помощью TypeScript или Facebook’s Flow, имеющими встроенную поддержку JSX.
  • Переход между версиями, как правило, очень прост: Facebook предоставляет «кодовые модули» для автоматизации большей части процесса.
  • Навыки, полученные в React, могут быть применены к разработке на React Native.

Недостатки React:

  • Сообщество делится по способам написания CSS в React, которые разделяются на традиционные таблицы стилей (CSS Modules) и CSS-in-JS (т.е. Emotion и Styled Components).
  • React отходит от компонентов на основе классов, что может стать препятствием для разработчиков, которым более комфортно работать с объектно-ориентированным программированием (ООП).
  • Смешивание шаблонов с логикой (JSX) может сбить с толку некоторых разработчиков при первых знакомствах с React.

Плюсы и минусы Vue

Vue— это JavaScript-фреймворк, основанный в 2013 году, который идеально подходит для создания высокоадаптируемых пользовательских интерфейсов и сложных одностраничных приложений.

Преимущества Vue:

  • Усиленный HTML. Это означает, что Vue.js имеет много характеристик схожих с Angular, а это, благодаря использованию различных компонентов, помогает оптимизации HTML- блоков.
  • Подробная документация. Vue.js имеет очень подробную документацию, которая может ускорить процесс обучения для разработчиков и сэкономить много времени на разработку приложения, используя только базовые знания HTML и JavaScript.
  • Адаптивность. Может быть осуществлен быстрый переход от других фреймворков к Vue.js из-за сходства с Angular и React с точки зрения дизайна и архитектуры.
  • Потрясающая интеграция. Vue.js можно использовать как для создания одностраничных приложений, так и для более сложных веб-интерфейсов приложений. Важно, что небольшие интерактивные элементы можно легко интегрировать в существующую инфраструктуру без негативных последствий.
  • Масштабирование. Vue.js может помочь в разработке довольно больших шаблонов многократного использования, которые могут быть сделаны почти за тоже время, что и более простые. Крошечный размер. Vue.js весит около 20 КБ, сохраняя при этом свою скорость и гибкость, что позволяет достичь гораздо лучшей производительности по сравнению с другими платформами.

Недостатки Vue:

  • Недостаток ресурсов. Vue.js по-прежнему занимает довольно небольшую долю рынка по сравнению с React или Angular, что означает, что обмен знаниями в этой среде все еще находится на начальной стадии.
  • Риск чрезмерной гибкости. Иногда у Vue.js могут возникнуть проблемы при интеграции в огромные проекты, и пока еще нет опыта возможных решений, но они обязательно появятся в ближайшее время.

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

Теперь нужно определиться, что будет отвечать за состояние приложения. На рынке представлены 2 популярных решения – это Redux и MobX.

Обе библиотеки используются для управления состоянием в JavaScript-приложениях.

Redux разработанный Дэном Абрамовым и Эндрю Кларком является производным архитектуры Flux. В отличие от Flux, он использует одно хранилище над несколькими для сохранения состояния. Кроме того, вместо диспетчера он использует чистые функции для изменения состояния.

Чистая функция — функция которая получает вход, возвращает выход и не имеет других зависимостей, кроме таких же функций. Такая функция производит всегда один и тот же выход с одним и тем же входом и не имеет никаких побочных эффектов.

Redux мастерски справляется со сложными взаимодействиями состояний, которые трудно передать с помощью состояния компонента React. По сути, это система передачи сообщений, которая встречается и в объектно-ориентированном программировании, но она не встроена непосредственно в язык, а реализована в виде библиотеки. Подобно ООП, Redux переводит контроль от вызывающего объекта к получателю — интерфейс не управляет состоянием напрямую, а передает ему сообщение для обработки.

MobX разработанный Мишелем Вестстратом, влияет не только объектно-ориентированное программирование, но также и реактивное программирование. Он обертывает ваше состояние в наблюдаемые объекты. Таким образом, у вас есть все возможности "Observable" в вашем состоянии. Данные могут иметь простые сеттеры и геттеры, но наблюдаемое позволяет получать обновления после изменения данных. В Mobx состояние изменчиво. Таким образом, можно менять состояние на прямую.

Я остановился на Redux, причина похожа почему я выбрал React, Redux более популярный, да и более простой, много справочных материалов + у него есть специальная библиотека react-redux, которая упрощает связку между react и redux путем добавления вспомогательных функций.

ТРЕБОВАНИЯ К САЙТУ.

ТРЕБОВАНИЯ К ФУНКЦИОНАЛЬНЫМ ХАРАКТЕРИСТИКАМ

Интернет-блог должен соответствовать следующим функциональным характеристикам:

  • интерфейс должен быть интуитивно понятен;
  • навигация по сайту должна быть максимально простой;
  • правильная адресация ссылок, чтобы пользователь мог просто и быстро перейти на любую страницу узла.
  • сайт должен быть разработан в едином стиле. Дизайн должен быть выполнен не в ущерб удобству навигации по сайту.

2.3 ТРЕБОВАНИЯ К СОСТАВУ И ПАРАМЕТРАМ ТЕХНИЧЕСКИХ СРЕДСТВ

Для нормальной бесперебойной работы программного средства необходимо выполнить ряд требований к аппаратному обеспечению:

  • процессор Pentium, Intel (R) i5-2430TM;
  • оперативная память 128 MB RAM (минимум). Рекомендуется 256 MB RAM;
  • видеоадаптер любой выпущенный позже 2000 год;
  • манипулятор "мышь";
  • клавиатура;
  • Windows XP или более новая версия. На ПК пользователя должно быть установлено следующее ПО, например, как интернет браузер: Mozilla Firefox, Google и т.д.

ПРАКТИЧЕСКАЯ ЧАСТЬ

ПРОЕКТИРОВАНИЕ ДИЗАЙНА

Как было сказано ранее, дизайн должен быть простым и интуитивным для пользователя. Проектировать буду в figma, на главной странице будет шапка, в которой будет название и выбор авторизация или регистрация, ниже сам контент из сообщений блога, а под ним для удобства выбор страниц, в итоге главная страница приобретет следующий вид:

После авторизации или регистрации, заменим кнопки входа и регистрации на создать статью, имя пользователя с его аватаркой и кнопкой выхода:

Страница регистрации будет иметь следующий вид:

Страница входа:

Страница создания новой записи приобретет следующий вид:

Так же нужно продумать как будет выглядить отдельно страница записи, и если запись конкретного пользователя, который ее оставил еще вывести кнопки удаления и редактирования, данная страница будет выглядеть следующим образом:

Нельзя забыть про редактирование профиля пользователя:

СОЗДАНИЕ САЙТА

Теперь когда макет готов можно перейти к непосредственно самой разработке интернет-блога.

Установим Node.js с оффициального сайта, для возможности устанавливать зависимости к проекту.

После перейдем в терминале в нужную директорию и пропишем create-react-app для создания базового проекта. После нужно продумать основные компоненты из которых будет состоять приложение, в итоге оно будет иметь следующую древовидную структуру:

Во вкладке components находятся основные компоненты, которые будут отрисовываться на странице, redux – в ней находятся файлы для управления состоянием, containers выступает в роли связующего, компоненты в ней связывают redux с react, в fonts лежат шрифты, в icons картинки, в services лежат файлы с отправкой запросов, в shared переиспользуемые компоненты или стили.

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

После этого переходим к хранению состояния. В крации редакс работает следующим образом:

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

У нас есть создание записи, за это отвечает файл create-article.jsx, код которого:

import React, { useEffect } from 'react';
import 'antd/dist/antd.css';
import './create-article.scss';
import { message } from 'antd';
import {Redirect } from 'react-router-dom';
import PropTypes from 'prop-types';
import ArticleForm from '../../shared/article-form';
import { LoadingOutlined } from '@ant-design/icons';

const CreateArticle = ({ article, user, successCreating, error, asyncCreateArticle, reset, successfullDownload }) => {
useEffect(() => {
return reset;
}, [reset]);

if (!Object.keys(user).length) {
return <Redirect to="/sign-in"/>;
}

if(error){
message.error('Failed');
}
if(!successfullDownload) {
if (successCreating) {
message.success('Success');
return <Redirect to="/"/>;
}
return <LoadingOutlined className="spinner" spin />;
}

return (
<ArticleForm user={user}
error={error}
article={article}
mission="create"
successCreating={successCreating}
reset={reset}
asyncCreateArticle={asyncCreateArticle}
/>
);
};

CreateArticle.propTypes = {
user: PropTypes.shape({
id: PropTypes.number,
email: PropTypes.string,
createdAt: PropTypes.string,
updatedAt: PropTypes.string,
username: PropTypes.string,
bio: PropTypes.string,
image: PropTypes.string,
token: PropTypes.string,
}).isRequired,
article: PropTypes.shape({
slug: PropTypes.string,
title: PropTypes.string,
description: PropTypes.string,
body: PropTypes.string,
tagList: PropTypes.arrayOf(PropTypes.string),
createdAt: PropTypes.string,
updatedAt: PropTypes.string,

}).isRequired,
successCreating: PropTypes.bool.isRequired,
error: PropTypes.bool.isRequired,
asyncCreateArticle:PropTypes.func.isRequired,
reset: PropTypes.func.isRequired,
};

export default CreateArticle;

Функции asyncCreateArticle, reset и состояния: article, user, succesCreating, error, successfullDownload берутся из связющего файла create-article-container.jsx, код которого:

import { connect } from 'react-redux';
import CreateArticle from '../../components/create-article';
import { asyncCreateArticle, reset } from '../../redux/action-creators';
import {
getError,
getLastOpenedArticle,
getSuccessCreatingArticle,
getSuccessfullDownload,
getUser,
} from '../../redux/users-selectors';

const mapStateToProps = (state) => ({
article: getLastOpenedArticle(state),
user: getUser(state),
successCreating: getSuccessCreatingArticle(state),
error: getError(state),
successfullDownload: getSuccessfullDownload(state),
});

const mapDispatchToProps = {
asyncCreateArticle,
reset,
};

export default connect(mapStateToProps, mapDispatchToProps)(CreateArticle);

Функция connect упрощает процесс связки react’a и redux, первым параметром указывается функция или объект хранящее в себя поля состояния, вторым параметром объект хранящий в себе функции action’ов.

В create-article.jsx все упирается в компоненту ArticleForm, это компонента предназначена как для создания записи, так и для ее редактирования, ее код:

import React, { useEffect } from 'react';
import 'antd/dist/antd.css';
import { Form, Input, Button, message } from 'antd';
import PropTypes from 'prop-types';

const formItemLayout = {
labelCol: {
xs: {
span: 24,
},
},
};
const tailFormItemLayout = {
wrapperCol: {
xs: {
span: 24,
offset: 0,
},
},
};

const formItemLayoutWithOutLabel = {
wrapperCol: {
xs: { span: 24, offset: 0 },
sm: { span: 20, offset: 4 },
},
};

const ArticleForm = ({ article, user, error, asyncCreateArticle, reset, mission, asyncEditArticle }) => {
useEffect(() => {
return reset;
}, [reset]);


const {slug} = article;
const [form] = Form.useForm();

const onFinish = ({ title, shortDescription, text, tagList}) => {
if(error) message.error('Failed');

if(mission === 'edit') {
return asyncEditArticle(user.token, title, shortDescription, text, tagList, slug)
}
return asyncCreateArticle(user.token, title, shortDescription, text, tagList);
};

const head = mission === "edit" ? 'Edit Article' : 'Create new article';

const initialValues = mission === 'edit' ? {
title: article.title,
shortDescription: article.description,
text: article.body,
tagList:article.tagList,
} : null;

return (
<Form
{...formItemLayout}
className="form form__create"
form={form}
name="register"
onFinish={onFinish}
scrollToFirstError
initialValues
={initialValues}
>
<h2>{head}</h2>
<Form.Item
name="title"
label="Title"
className="form__item"
rules={[
{
required: true,
message: 'Please input title',
whitespace: true,
},
() =>({
validator(rule, value){
if(value.length > 16){
return Promise.reject(
"Title must be less then 16 characters"
);
}
return Promise.resolve();
}
})
]}
>
<Input placeholder="Title" className="form__input"/>
</Form.Item>

<Form.Item
name="shortDescription"
label="Short description"
className="form__item"
rules={[
{
required: true,
message: 'Please input short description',
},
() =>({
validator(rule, value){
if(value.length > 32){
return Promise.reject(
"Short description must be less then 32 characters"
);
}
return Promise.resolve();
}
})
]}
>
<Input placeholder="Description" className="form__input"/>
</Form.Item>

<Form.Item
name="text"
label="Text"
className="form__item"
rules={[
{
required: true,
message: 'Please enter text article',
},
]}
>
<Input.TextArea placeholder="Text" className="form__input" style={{ height: 168 }}/>
</Form.Item>

<Form.List name="tagList">
{(fields, { add, remove }, { errors }) => (
<>
{fields.map((field, index) => (

<Form.Item
{...(index === 0 ? formItemLayout : formItemLayoutWithOutLabel)}
required={false}
key={field.key}
className="form__row"
>
<Form.Item
style={{ marginLeft: 0}}
{...field}
validateTrigger={['onChange', 'onBlur']}
rules={[
{
required: true,
whitespace: true,
message: 'Please input tag or delete this field.',
},
]}
noStyle
>
<Input placeholder="Tag" className="input__tag"/>
</Form.Item>

<Button
className="btn__tag btn__tag-del"
type="danger" ghost
onClick
={() => remove(field.name)}
>Delete</Button>
<Button
className="btn__tag btn__tag-add"
type="primary" ghost
onClick
={() => add()}
>Add Tag</Button>

</Form.Item>
))}

{(fields.length === 0) ? <Form.Item style={{textAlign: 'left'}}>
<Button
type="primary" ghost
className
="btn__tag btn__tag-add"
onClick={() => add()}
>
Add tag
</Button>
<Form.ErrorList errors={errors}/>
</Form.Item> : null}
</>
)}
</Form.List>

<Form.Item {...tailFormItemLayout} style={{textAlign:'left'}}>
<Button type="primary"
className="btn__save"
block
htmlType
="submit">
Save
</Button>
</Form.Item>
</Form>
);
};

ArticleForm.defaultProps = {
asyncEditArticle: () => {},
asyncCreateArticle: () => {},
reset: () => {},
successEditing: false,
mission: '',
}

ArticleForm.propTypes = {
user: PropTypes.shape({
id: PropTypes.number,
email: PropTypes.string,
createdAt: PropTypes.string,
updatedAt: PropTypes.string,
username: PropTypes.string,
bio: PropTypes.string,
image: PropTypes.string,
token: PropTypes.string,
}).isRequired,
article: PropTypes.shape({
slug: PropTypes.string,
title: PropTypes.string,
description: PropTypes.string,
body: PropTypes.string,
tagList: PropTypes.arrayOf(PropTypes.string),
createdAt: PropTypes.string,
updatedAt: PropTypes.string,

}).isRequired,
error: PropTypes.bool.isRequired,
asyncEditArticle:PropTypes.func,
asyncCreateArticle:PropTypes.func,
reset: PropTypes.func.isRequired,
mission: PropTypes.string,
};

export default ArticleForm;

Т.к я взял за пример создание записи, будем рассматривать только этот случай, при нажатии кнопки создать и при прохождении проверок, что все поля не пустые вызовится функция onFinish, которая в свою очередь вызовет asyncCreateArticle(это наш action) и передаст в него те данные, которые пользоветь хочет отобразить в записи. Код asyncCreateArticle находится в файле action-creators.js и его код следующий:

export const asyncCreateArticle = (token, title, description, body, tagList) => {
return async function inside(dispatch) {
try {
dispatch(reset());
await createArticle(token, title, description, body, tagList);
dispatch(articleCreated());
} catch (error) {
dispatch(articleNotCreated());
}
};
};

В этой функции dispatch приходится связующим между action’ом и reducer’ом, вызывается функция reset и articleCreated, в случае ошибки articleNotCreated, для примера рассмотрим код и логику работы функции articleCreated(с остальными по аналогии):

const articleCreated = () => ({
type: ARTICLE_CREATED,
});

в ней указан тип ‘ARTICLE_CREATED’ при срабатывании которого вызывается функция с данным типом в reducer’e:

const successCreatingArticle = (state = false, action) => {
switch (action.type) {
case ARTICLE_CREATED:
return true;
case RESET:
return false;
default:
return state;
}
}

У каждой такой функции есть собственное состояние(state), которое в данном случае равно false, и при успешном создании возвращается true, на этом завязан еще и некий интерактив, ведь когда пользователь нажал на создание записи, то процесс отправки запроса на сервер и обратно занимает некоторое время и пользователь должен сразу понимать, что идет загрузка, в коде выше есть проверка, повторю его:

if(!successfullDownload) {
if (successCreating) {
message.success('Success');
return <Redirect to="/"/>;
}
return <LoadingOutlined className="spinner" spin />;
}

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

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

Главное меню после загрузки выглядит следующим образом:

Из важного на ней указан домейн, сама ссылка по которой доступен сайт, state – скомпилировался ли сайт.

ЗАКЛЮЧЕНИЕ

В ходе выполнения данной курсовой работы мною была проделана не малая работа, я проанализировал рынок технологий, выбрал связку react + redux и изучил ее, вследствие чего сделал сайт блог на основе выбранного стека и развернул данное приложение в сеть интернет.

Целью моей курсовой работы являлось создание полноценного функционирующего блога в сети интернет. Цель полностью выполнена.

Итоговый код проекта:

https://github.com/AlDAani/Blog

Ссылка на сам сайт:

https://blog-coral-kappa.vercel.app/

СПИСОК ЛИТЕРАТУРЫ

Сравнение фреймворков:

https://habr.com/ru/post/476312/

Про MobX и Redux:

https://habr.com/ru/post/476312/

https://habr.com/ru/post/333848/

Документация к api сервера:

https://github.com/gothinkster/realworld/tree/master/api

Документация react’a:

https://reactjs.org/docs/getting-started.html

Документация redux’a:

https://redux.js.org/