Поговорим о нашем домашнем задании. Стоит отметить что при разработке 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
Пожалуйста сравните наш код с тем что у Вас получился, и мы пойдем дальше. Все коммиты Вы сможете найти в репозитории.
We are looking forward to meeting you on our website blog.soshace.com


