Best practice SPA with React
Віртуальний DOM
Кожного разу, коли відбувається зміна стану, Реакт будує новий віртуальни DOM для всього, що знаходиться нижче в ієрархії
Основні терміни
- props - Данні, котрі приходять "зверху", від батьківського елементу
- state - Данні, котрі відповідають за стан цього компоненту, "зверху" про нього нічого не знають
- keys - ідентифікують реальні DOM-ноди, необхідні для відображення масивів
- refs - посилання на реальну DOM-ноду, в котрій міститься React-компонент
Flux
- Основна ідея Flux - односторонній потік данних.
- Actions диспатчаться в усі Store, обробляються, і вже нові данні відправляються в React.
- На відміну від MVC, нам не важливо що саме змінилось - React всеодно збудує новий DOM
Action Creators
Функції, котрі описують дію. Використовуватимуться в UI
function addItem(data) {
Dispatcher.dispatch({
type: ADD_ITEM,
data
})
}
Найпростіший AC абстаргує нас від диспетчера, в мабутньому може бути ускладнений
Хороша практика: використання констант для опису типів подій(в цьому випадку ADD_ITEM)
Async AC
В класичному Flux коммунікації з API виносяться в
Action Creators
function loadItem(id) {
Dispatcher.dispatch({
type: LOAD_ITEM_START,
data: { id }
})
$.get(`/api/items/${id}`)
.done((response) => {
Dispatcher.dispatch({
type: LOAD_ITEM_SUCCESS,
data: { response }
})
})
.fail((error) => {
Dispatcher.dispatch({
type: LOAD_ITEM_FAIL,
data: { id, error }
})
})
}
Store
Найпростіший Store відповідає за роботу з данними
і повідомляє про їх зміни
class AbstractStore extends EventEmitter {
constructor() {
super()
this.__items = []
}
emitChange() {
this.emit(STORE_CHANGE_EVENT)
}
addChangeListener(callback) {
this.on(STORE_CHANGE_EVENT, callback)
}
removeChangeListener(callback) {
this.removeListener(STORE_CHANGE_EVENT, callback)
}
getAll() {
return this.__items
}
add(item) {
this.__items.push(item)
}
}
Складніший Store
Деякі Store Мусять реагувати на події
class ItemStore extends AbstractStore {
constructor() {
super()
this.dispatchToken = Dispatcher.register((action) => {
const { data, type } = action
switch (type) {
case ADD_ITEM:
this.add(data)
this.emitChange()
break;
}
})
}
}
В такий Store завжди потраплятимуть всі події з диспетчеру, він сам муисть визначити на які реагувати, а які ігнорувати
React-router
<Router history = {createBrowserHistory()}>
<Route path = "/" component = {App} onEnter = {checkAuth}>
<IndexRoute component = {ArticleList} />
<Route path = "new" component = {NewArticle} />
<Route path = "/:id" component = {ArticlePage} />
</Route>
<Route path="*" component = {NotFound} />
</Router>
- react-router дозволяє декларативно описувати ваші роути
- За кожен роут відповідає один компонент
- Якщо роут має вкладені роути, то вкладені компоненти передаватимуться як props.children
- Роути мають хуки, такі як onEnter і onLeave, котрі дозволяють перевіряти права, отримувати необхідні данні, та за потреби скасовувати перехід
- history відповідає за те, як виглядатиме url ('/#/new' - HashHistory, '/new' - BrowserHistory)
Best practice SPA with React
By Roman Iakobchuk
Best practice SPA with React
- 1,199