Skip to content
Open

Hw 6 #85

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions src/AC/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {
INCREMENT, DELETE_ARTICLE, CHANGE_DATE_RANGE, CHANGE_SELECTION, ADD_COMMENT, LOAD_ALL_ARTICLES, LOAD_ARTICLE,
START, SUCCESS, FAIL
INCREMENT, DELETE_ARTICLE, CHANGE_DATE_RANGE, CHANGE_SELECTION, ADD_COMMENT, LOAD_ALL_ARTICLES,
LOAD_ARTICLE, LOAD_COMMENTS, START, SUCCESS, FAIL
} from '../constants'

export function increment() {
Expand Down Expand Up @@ -72,4 +72,12 @@ export function loadArticle(id) {

}, 1000)
}
}

export function loadComments(articleId) {
return {
type: LOAD_COMMENTS,
payload: { articleId },
callAPI: `/api/comment?article=${articleId}`
}
}
21 changes: 18 additions & 3 deletions src/components/Article/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {connect} from 'react-redux'
import CommentList from '../CommentList'
import Loader from '../common/Loader'
import {deleteArticle, loadArticle} from '../../AC'
import {commentsLoadingSelector, commentsLoadedSelector} from '../../selectors'
import './style.css'

class Article extends PureComponent {
Expand Down Expand Up @@ -61,14 +62,15 @@ class Article extends PureComponent {
}

getBody() {
const { isOpen, article } = this.props
const { isOpen, article, loadingComments, loadedComments } = this.props
if (!isOpen) return null
if (article.loading) return <Loader/>

return (
<div>
<section>{article.text}</section>
<CommentList article = {article} ref = {this.setCommentsRef} key = {this.state.count}/>
<CommentList article = {article} loading = {loadingComments} loaded = {loadedComments}
ref = {this.setCommentsRef} key = {this.state.count}/>
</div>
)

Expand Down Expand Up @@ -97,5 +99,18 @@ class Article extends PureComponent {

}

const createMapStateToProps = () => {
return (state, ownProps) => {
const articleId = ownProps.article.id
const loading = commentsLoadingSelector(state)
const loadingComments = loading.get(articleId) != null ? loading.get(articleId) : true
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

почему бы не сделать сразу для этого селектор?

const loaded = commentsLoadedSelector(state)
const loadedComments = loaded.get(articleId)
return {
loadingComments: loadingComments,
loadedComments: loadedComments
}
}
}

export default connect(null, { deleteArticle, loadArticle })(Article)
export default connect(createMapStateToProps, { deleteArticle, loadArticle })(Article)
10 changes: 9 additions & 1 deletion src/components/CommentList.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ import PropTypes from 'prop-types'
import CommentForm from './CommentForm'
import Comment from './Comment'
import toggleOpen from '../decorators/toggleOpen'
import {loadComments} from '../AC'
import Loader from './common/Loader'
import store from '../store'

class CommentList extends Component {
static propTypes = {
Expand All @@ -12,6 +15,10 @@ class CommentList extends Component {
toggleOpen: PropTypes.func
}

componentWillReceiveProps({ isOpen, article, loaded}) {
if (!this.props.isOpen && isOpen && !loaded) store.dispatch(loadComments(article.id))
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Не обращайся к стору явно, если очень хочешь использовать dispatch - заворачивай в коннект и бери из пропсов

}

render() {
const {isOpen, toggleOpen} = this.props
const text = isOpen ? 'hide comments' : 'show comments'
Expand All @@ -24,9 +31,10 @@ class CommentList extends Component {
}

getBody() {
const {article: { comments, id }, isOpen} = this.props
const {article: { comments, id }, isOpen, loading} = this.props
if (!isOpen) return null

if (loading) return <Loader />
const body = comments.length ? (
<ul>
{comments.map(id => <li key = {id}><Comment id = {id} /></li>)}
Expand Down
1 change: 1 addition & 0 deletions src/constants/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export const CHANGE_SELECTION = 'CHANGE_SELECTION'
export const CHANGE_DATE_RANGE = 'CHANGE_DATE_RANGE'

export const ADD_COMMENT = 'ADD_COMMENT'
export const LOAD_COMMENTS = 'LOAD_COMMENTS'

export const START = '_START'
export const SUCCESS = '_SUCCESS'
Expand Down
42 changes: 34 additions & 8 deletions src/reducer/comments.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,42 @@
import { ADD_COMMENT } from '../constants'
import {normalizedComments} from '../fixtures'
import { Map, Record } from 'immutable'
import { ADD_COMMENT, LOAD_COMMENTS, START, SUCCESS } from '../constants'
import {arrToMap} from './utils'

export default (state = arrToMap(normalizedComments), action) => {
const { type, payload, randomId } = action
const CommentRecord = Record({
id: null,
user: null,
text: null,
})

const idRecord = Record({
id: null
})

const ReducerRecord = Record({
entities: arrToMap([], CommentRecord),
loading: arrToMap([], idRecord),
loaded: arrToMap([], idRecord),
error: arrToMap([], idRecord)
})

export default (state = new ReducerRecord(), action) => {
const { type, payload, randomId} = action

switch (type) {
case ADD_COMMENT:
return state.set(randomId, {
...payload.comment,
id: randomId
})
return state.mergeIn(['entities'], arrToMap([{
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Почему не просто setIn(['entities', id], new Record())

id: randomId,
user: payload.comment.user,
text: payload.comment.text
}], CommentRecord))
case LOAD_COMMENTS + START:
return state.setIn(['loading', payload.articleId], true)
case LOAD_COMMENTS + SUCCESS:
const { response } = action
return state
.setIn(['loading', payload.articleId], false)
.setIn(['loaded', payload.articleId], true)
.mergeIn(['entities'], arrToMap(response, CommentRecord))
}

return state
Expand Down
6 changes: 4 additions & 2 deletions src/selectors/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ import {createSelector} from 'reselect'
export const articlesMapSelector = state => state.articles.entities
export const articlesLoadingSelector = state => state.articles.loading
export const filtersSelector = state => state.filters
export const commentListSelector = state => state.comments
export const commentsMapSelector = state => state.comments.entities
export const commentsLoadingSelector = state => state.comments.loading
export const commentsLoadedSelector = state => state.comments.loaded
export const idSelector = (_, props) => props.id

export const articlesSelector = createSelector(articlesMapSelector, articles => articles.valueSeq().toArray())
Expand All @@ -18,6 +20,6 @@ export const filtratedArticlesSelector = createSelector(articlesSelector, filter
})
})

export const createCommentSelector = () => createSelector(commentListSelector, idSelector, (comments, id) => {
export const createCommentSelector = () => createSelector(commentsMapSelector, idSelector, (comments, id) => {
return comments.get(id)
})