14Sep

a2a2543d-1502-4fac-9336-8f9627510105

Поговорим о нашем домашнем задании. Стоит отметить что при разработке decorators/mixins вся логика в большинстве случаев работает прекрасно. Она была реализована нами в классе, для выполнения домашнего задания оставалось вынести ее в decorator и соответствующий mixin. Так будет выглядеть наш decorator (src/decorators/oneOpen.js):

import React, { Component as ReactComponent} from 'react'

export default (Component) => class OneOpen extends ReactComponent {
    state = {
        openItemId: null
    }

    openItem = openItemId => ev => {
        if (ev) ev.preventDefault()
        this.setState({ openItemId })
    }

    toggleOpenItem = id => ev => {
        if (ev) ev.preventDefault()
        this.setState({
            openItemId: id == this.state.openItemId ? null : id
        })
    }

    isItemOpen = id => this.state.openItemId == id


    render() {
        return <Component {...this.props} isItemOpen = {this.isItemOpen} openItem = {this.openItem} toggleOpenItem  = {this.toggleOpenItem}/>
    }
}

Decorators и mixins создаются для того чтобы вы могли переиспользовать ваш код, т.е. написав его однажды,применять его в разных местах. То что сегодня работает для статей завтра будет работать для комментариев, авторов и.т.п. Поэтому при присваивании имен вашим сущностям делайте более универсальные названия. К примеру: openItem, openElement. Для того чтобы сделать опциональную часть домашнего задания достаточно проверить когда нам приходит id, совпадает ли он с тем который у нас уже храниться в state. Если да, это означает что нам нужно закрыть статью, чтобы это сделать достаточно присвоить null, а иначе мы просто поменяем id:

openItemId: id == this.state.openItemId ? null : id

Наш mixin (src/mixins/oneOpen.js) будет выглядеть следующим образом:

export default {
    getInitialState() {
        //this.props
        return {
            openItemId: false
        }
    },
    openItem(openItemId) {
        return ev => {
            if (ev) ev.preventDefault()
            this.setState({openItemId})
        }
    },

    toggleOpenItem(id) {
        return ev => {
            if (ev) ev.preventDefault()
            this.setState({
                openItemId: id == this.state.openItemId ? null : id
            })
        }
    },

    isItemOpen(id) {
        return this.state.openItemId == id
    }
}

Также  ArticleList.js измениться следующим образом:

import React, { Component }  from 'react'
import Article from './Article'
import oneOpen from './decorators/oneOpen'

class ArticleList extends Component {
    render() {
        const { articles, isItemOpen, toggleOpenItem } = this.props

        const listItems = articles.map((article) => <li key={article.id}>
            <Article article = {article}
                isOpen = {isItemOpen(article.id)}
                openArticle = {toggleOpenItem(article.id)}
            />
        </li>)
        return (
            <div>
                <h1>Article list</h1>
                <ul>
                    {listItems}
                </ul>
            </div>
        )
    }
}

export default oneOpen(ArticleList)

ArticleListOld.js будет выглядеть так:

import React, { Component }  from 'react'
import Article from './Article'
import oneOpen from './mixins/oneOpen'

const ArticleList = React.createClass({
    mixins: [oneOpen],
    render() {
        const { articles } = this.props

        const listItems = articles.map((article) => <li key={article.id}>
            <Article article = {article}
                isOpen = {this.isItemOpen(article.id)}
                openArticle = {this.toggleOpenItem(article.id)}
            />
        </li>)
        return (
            <div>
                <h1>Article list</h1>
                <ul>
                    {listItems}
                </ul>
            </div>
        )
    }
})

export default ArticleList

Пожалуйста добавьте следующую запись в app.js, и удалите import  ArticleList’а:

import ArticleList from './ArticleListOld

Пожалуйста сравните наш код с тем что у Вас получился, и мы пойдем дальше. Все коммиты Вы сможете найти в репозитории.

435258_8a75_3

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