Теперь давайте это вызовем в containers/Articles.js
, добавив такую запись вызывая action creater
:
import { loadAllArticles } from '../AC/articles' class Articles extends Component { static propTypes = { }; componentDidMount() { this.props.loadAllArticles() }
А ниже в connect
мы его обернем :
export default connect(({ articles, filters }) => { return { articles: filterArticles(articles, filters) } }, { loadAllArticles })(Articles)
А далее вызовем в componentDidMount()
.
Также в reducer/articles.js
мы уберем defaultArticles
которые мы с Вами создавали:
const defaultArticles = new OrderedMap({})
Не забудем подключить в import
объект OrderedMap
:
import { Record, OrderedMap } from 'immutable'
Теперь нужно подключить наш middleware
в нашем store
.
Делаем import
:
import api from '../middlewares/api'
И добавляем ее в ряд с другими middleware
например после randomID
:
const enhancer = compose( applyMiddleware(dumbMiddleware, randomId, api, logger), window.devToolsExtension ? window.devToolsExtension() : f => f )
Теперь если перезапустить приложение в console
можно увидеть что происходит LOAD_ALL_ARTICLES_SUCCESS
Давайте добавим setTimeout
для симуляции некого далекого API, добавим это в middlewares/api.js
:
setTimeout(() => { $.get(callAPI) .done(response => next({type: type + SUCCESS, response, ...rest})) .fail(error => next({type: type + FAIL, error, ...rest})) }, 1000) }
Теперь, если вы зайдет в console
и перезагрузите наше приложение, у Вас произойдут действия START
и через секунду SUCCESS
.
Теперь нам осталось научить наши reducers
обращаться с новой логикой. Перейдем в reducer/articles.js
. Здесь нам уже недостаточно просто иметь articles
в виде набора статей, поскольку наше приложение развивается, становиться более сложным, и появляется необходимость иметь информацию о статусе загрузки статей.
Подключим Map
а также immutable
массив List
из immutable.js
:
import { Record, OrderedMap, Map, List } from 'immutable'
Опишем начальное состояние нашего reducer
, добавив следующую запись:
const defaultState = new Map({ loading: false, loaded: false, errors: new List([]), entities: defaultArticles })
Добавив сюда сами статьи у нас получилась структура, которую мы сможем переиспользовать от одного reducer
к другому. Т.е. entities
у нас будут как статьи так и комментарии. Наш код ниже тоже претерпит изменения:
export default (state = defaultState, action) => { const { type, payload, response, randomId } = action switch (type) { case ADD_COMMENT: return state.updateIn(['entities' ,payload.articleId, 'comments'], comments => comments.concat(randomId)) case LOAD_ALL_ARTICLES + START: return state.set('loading', true) case LOAD_ALL_ARTICLES + SUCCESS: return state .set('loading', false) .set('entities', recordsFromArray(Article, response)) //return state.update('entities', entities => entities.merge(recordsFromArray(Article, response))) } return state }
Обратите Ваше внимание на закомментированную строку. Эта запись описывает подход как можно по-другому с помощью методов update
и merge
из immutable.js
загрузить наши статьи. В этом случаем мы делаем обновление списка наших статей. Когда у нас приходит LOAD_ALL_ARTICLES + SUCCESS
мы берем старые entities
(если они у нас были) и делаем merge
с новыми. По умолчанию, процесс добавления статей будет реализован нами c помощью set
– т.е. просто полным обновлением списка. Мы добавили .set('loading', ...)
, для того чтобы можно было добавить loader
при загрузке наших статей.
Идем дальше, теперь нам нужно переписать логику того как мы получаем данные в filterArticles
в containers/Articles.js
а также добавить loader
в наш UI:
render() { const { articles, loading } = this.props if (loading) return <h1>Loading...</h1> return <ArticleList articles = {articles} /> } } export default connect(({ articles, filters }) => { return { loading: articles.get('loading'), articles: filterArticles(articles.get('entities'), filters) } }, { loadAllArticles })(Articles)
Мы добавили индикатор в export default
), а в render
простенький loader
. (когда мы закончим, до загрузки статей будет появлятся соответствующая надпись “Loading”).
В immutable.js
вы должны явно писать ваше обращение для того чтобы получить данные articles.get('entities')
. Когда мы использовали immutable object Record
мы могли избежать такого рода обращения, т.к. все происходило “под капотом” и getters, setters, создавались внутри, как в случае с const Article
в reducer/articles.js
.
Продолжим наши преобразования и изменим reducer/articles.js
следующим образом:
import { DELETE_ARTICLE, ADD_COMMENT, LOAD_ALL_ARTICLES, START, SUCCESS } from '../constants' import { Record, OrderedMap, Map, List } from 'immutable' import { recordsFromArray } from './utils'
ошибки мы с Вами пока обрабатывать пока не будем. Запись про import
normalizedArticles
нам здесь больше не понадобиться. Поменяем нашу константу defaultArticles
:
const defaultArticles = recordsFromArray(Article, [])
И конечно же return
в конце файла:
return state
Теперь все готово, можно проверять! Код нашего урока доступен по этой ссылке. До скорых встреч, дальше еще очень много интересного, увидимся!
We are looking forward to meeting you on our website soshace.com