Skip to content

Instantly share code, notes, and snippets.

@SergProduction
Last active April 15, 2018 22:54
Show Gist options
  • Save SergProduction/9364856c3cbe3d87cf64be4f5931c6ef to your computer and use it in GitHub Desktop.
Save SergProduction/9364856c3cbe3d87cf64be4f5931c6ef to your computer and use it in GitHub Desktop.

Архитектура проэкта на реакте

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

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

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

<BrowserRouter>
  <Menu> {/* какой-то общий компонент который должен отображаться еа всех страницах*/}
  <Switch>
    <Route path="/" component={Component} />
    {/*...  все остальные динамичесие роуты*/}
  </Switch>
<BrowserRouter>

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

// other.js
const Other = props => (
  <React.Fragment>
    <OtherMenu> {/* какой-то общий компонент который должен отображаться еа всех страницах*/}
    <Switch>
      <Route path="/" component={ComponentOther} />
      {/*...  все остальные динамичесие роуты*/}
    </Switch>
  </React.Fragment>
)

// index.js
<BrowserRouter>
  <Menu> {/* какой-то общий компонент который должен отображаться еа всех страницах*/}
  <Switch>
    <Route path="/" component={Component} />
    <Route path="/other" component={Other} />
    {/*...  все остальные динамичесие роуты*/}
  </Switch>
<BrowserRouter>

Держать такие компоненты можно в папке routes, где index - компонент с роунгом верхнего уровня, и подуровневые компоенты роутинга называть по сущьностям которые они отображают.

/routes
  index.js
  other.js

Теперь о том как отображать данные во вью, обычно если нужно отображать данные от апи, то часто в каждом компоненте вызывают метод апи, в жизненым цикле вью компонента componentDidMount, так же может понадобиться вызывать новые данные в зависимости от роутинга, если в роугинте обозначенно, что по какому-что роуту, можно отобразить данные по id, например /news/:id, поэтому нам нужно будет следить за props.match.params.id в методе componentWillReceiveProps. В таком случае мы можем вынести данную логику в компонент высшего порядка - HOC

export const hocNews = WrappedComponent => class News extends Components {
  state = {news: null}

  componentDidMount() {
    this.getNews(this.props.match.params.id)
  }

  componentWillReceiveProps(nextProps){
    this.getNews(nextProps.match.params.id)
  }

  getNews = id => {
    api.news.getNews(id)
      .then(news => {
        this.setState({news})
      })
  }

  render() {
    return <WrappedComponent news={this.state.news} {...this.props}/>
  }
}

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

/hocs
import hocNews from './hocs/news'
import ViewNews from './view/news'

const News = hocNews(ViewNews)

<BrowserRouter>
  <Switch>
    <Route path="/news:id" component={News} />

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

/hocs
  /users
    actions.js
    reducer.js
    index.js

апи. Может быть несколько разных серверов, с которых мы может запросить данные, для каждого сервера может быть свой http конфиг запроса например работа с заголовками, сесией, поэтому должен быть один файл который будет объеденять все апи методы, структура директорий файлов может выглядить следующим образом

/api
  index.js
  news.js
  user.js
  ...

Обращения к методам апи должно из приложения должно быть через файл /api/index.js где должны быть описанны все методы, и желательно типы данных которые могут возращать методы, чтоб пользуясь апи, не писать каждый раз console.log чтоб знать с какими данными приходиться работать. /api/index.js должен выглядить примерно следующим образом

import news from './news'
import user from './user'

const craeteApi = myapi = ({
  news: {
    getNews: myapi.news.getNews,
  }
  users: {
    singIn: myapi.news.singIn,
    singUp: myapi.news.singUp,
  }
})

export const api = craeteApi({
  news: news,
  users: user,
})

Переменные окружения. Их можно хранить в корне проэкта, и пробрасывать в приложение через webpack EnvironmentPlugin, в коде можно к ним обриться через proccess.env, при компиляции, такие переменные в коде заменятсья зачениями из env файла

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

/core
  /hocs
  /api

/oneProject
  /routes
  /view
  /store
  /img
  /css
  /fonts
  index.html

/twoProject
  /routes
  /view
  /store
  /img
  /css
  /fonts
  index.html

В дополнение к расширении проэкта, может понадобиться заменить апи, которые предоставляет те же данные, но в другой структуре, чтоб не менять все хоки и вью, которые работают с этими данными, можно написать нормалайзы - ф-цию которые преобразовывают одну структуру данных в другую, если в index.api были описанны типы данных (flow, ts), то написать такие нормалайзы не быть сложной задачей, так как все структуры описанны и на виду, выглядить это можкт слудующшим образом

/api
  /user
    api.js (конфиг http запроса к серверу с методами)
    index.js (нормалайз)
  index.js

где api/index.js импортирует файл с уже нормализованными данными под приложение

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment