10Nov

react-logo_13_2

Теперь давайте это вызовем в 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'

ошибки мы с Вами пока обрабатывать пока не будем. Запись про importnormalizedArticles нам здесь больше не понадобиться. Поменяем нашу константу defaultArticles :

const defaultArticles = recordsFromArray(Article, [])

И конечно же return в конце файла:

return state

Теперь все готово, можно проверять! Код нашего урока доступен по этой ссылке. До скорых встреч, дальше еще очень много интересного, увидимся!

react-boilerplate

We are looking forward to meeting you on our website soshace.com

Leave a Reply