Поговорим о нашем домашнем задании. Стоит отметить что при разработке 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 soshace.com