Идея проекта

Для моего последнего школьного проекта в школе Flatiron я создал приложение под названием Внимательный ребенок — простое приложение, позволяющее мамам проводить моменты осознанности со своими детьми. Практика осознанности может помочь детям замечать положительные стороны и развивать чувство признательности и благодарности. Пользователи могут щелкнуть категорию, которая приведет к видео с осознанием активности в этой конкретной категории. Если пользователи хотят видеть все 3 категории, они могут сделать это, а также подписаться на информационный бюллетень приложения.

Структура проекта

Шаг 1: Настройка API Rails

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

Ассоциации

Категория
has_many :activities
Деятельность
принадлежит_к: категория

Настройка моделей
rails g resource Название категории:string — no-test-framework
rails g resource Название действия:string description:string category_id:integer url:string — no -тест-фреймворк

создал seed.file

Я использовал файл db/seeds.rb, потому что он предлагает простой механизм заполнения пустой базы данных значениями по умолчанию.

Скачать Cors

Обеспечивает поддержку общего доступа к ресурсам между источниками (CORS).

Созданные действия
Действия
Категории

Добавлен сериализатор

ActiveModel::Serializer — Сериализатор облегчает отношения, созданные в бэкэнде, а затем транслирует их во внешний интерфейс.

Обратите внимание, что контроллер находится под app/controllers/api/v1, потому что я управляю версиями своего API. Это хорошая практика, позволяющая избежать критических изменений и обеспечить некоторую обратную совместимость с API. См. пример ниже.

namespace :api do
  namespace :v1 do
    resources :categories do
    resources :activities
    end 
  end
end

Шаг 2: Создать-реагировать-приложение

Я использовал генератор create-react-app, чтобы начать свой проект. В среде будет все необходимое для создания одностраничного приложения React. Настройте файлы действий, компонентов, контейнеров и редукторов.

Шаг 3: React-Redux

В проект добавлен React-Redux. Я использовал некоторые компоненты и функции, чтобы связать React и Redux вместе: Store, Provider и Connect.

Шаблон Redux, в котором хранилище отправляет действие редюсеру, который затем берет эту информацию в объекте действия для внесения изменений в состояние, что, в свою очередь, вызывает повторную визуализацию компонентов с новыми данными. -Утюг

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux'
import store from './store.js'
import App from './App';

import 'bootstrap/dist/css/bootstrap.min.css';

ReactDOM.render(
  <Provider store={ store }>  
        <App /> 
  </Provider>, document.getElementById('root')
);

Промежуточное ПО Redux-Thunk

Когда пользователь нажимает на кнопку, мы вызываем функцию handleChange(). Это вызывает нашего создателя действия, функцию fetchCategories(). Затем создатель действия обращается к API и возвращает действие с нашими данными, которые затем обновляют состояние через редьюсер. Запрос fetch() возвращает нечто, называемое Promise. Объект Promise — это объект, представляющий некоторое значение, которое будет доступно позже. Мы можем получить доступ к данным, когда обещание «разрешится» и станет доступным, привязав функцию .then() к нашему вызову fetch(). См. пример ниже.

export function fetchCategories () {
return (dispatch) => {
fetch(‘http://localhost:3000/api/v1/categories')
.then(resp => resp.json())
.then(categories => dispatch({
type: ‘FETCH_CATEGORIES’,
payload: categories
   }))
  }
}
____________________________________________________________________
...imports goes here...
class Newsletter extends React.Component{
...more code goes here....

    //update state with setState
    handleChange = (event) => {
        this.setState({
            email: event.target.value
        });
    }
...more code goes here....


export default connect(null,{addEmail})(Newsletter)

Обратите внимание, что веб-запросы в JavaScript являются асинхронными.

Это означает, что если мы сделаем веб-запрос в первой строке нашей функции fetchCategories(). При извлечении данных из API мы сталкиваемся с проблемой, когда создатель действия возвращает действие до получения данных. Чтобы решить эту проблему, я использовал промежуточное ПО под названием Thunk.

Помните, Thunk позволяет нам возвращать функцию внутри создателя действия вместо простого объекта JavaScript. Эта возвращенная функция получает функцию отправки хранилища, и с ее помощью мы можем отправлять несколько действий: одно для перевода состояния в состояние загрузки, а другое для обновления хранилища возвращенными данными. Чтобы использовать Thunk, следуйте инструкциям по установке пакета NPM.

Шаг 4: Маршрутизатор

Одним из требований для этого проекта было использование правильной маршрутизации RESTful, такой как React Router.

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

Я добавил Router в index.js, обертывающий дочерние компоненты ‹APP/›, и импортировал приведенные ниже.

import { BrowserRouter as Router, Route, Switch} from 'react-router-dom';
import 'bootstrap/dist/css/bootstrap.min.css';

class App extends React.Component{

  render() {
    return (
     <Router>
        <div className="App">    
          <Header/>
           <Switch>   
              <Route exact path='/categories' component=    {CategoriesContainer}/>
              <Route exact path='/newsletter' component={Newsletter}/>
              <Route  path='/categories/:id/activity' component={ActivitiesContainer}/>
              <Route exact path='/' component={Home}/>
              <Route path="*" component={NotFound} />
           </Switch>        
        </div>
     </Router>     
    ); 
  } 
}

export default App;

Компоненты

Я использовал компонент более высокого порядка, такой как connect(), в моих 2 компонентах-контейнерах. Мои7 презентационных компонентов не имеют состояния и принимают реквизиты из компонента-контейнера ине взаимодействуют с хранилищем Redux.

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

Вот короткая демонстрация моего приложения.

Спасибо, что прочитали этот пост в блоге, и большое спасибо Flatiron School.

Если у вас есть какие-либо комментарии или отзывы, пожалуйста, дайте мне знать. Вы можете увидеть весь код этого проекта на GitHub repo.

Дальнейшее чтение