From 326d9d615e8a8b3469a45ea0fcbc9752b0746d80 Mon Sep 17 00:00:00 2001 From: AbilityG Date: Thu, 8 Feb 2018 01:31:27 +0600 Subject: [PATCH 1/3] Hometask_06 --- src/AC/index.js | 23 ++++++++++++++-- src/components/Comment.js | 15 ++++------ src/components/CommentList.js | 23 ++++++++++++++-- src/constants/index.js | 1 + src/middlewares/api.js | 2 +- src/reducer/comments.js | 52 +++++++++++++++++++++++++++++------ src/selectors/index.js | 11 ++++++-- 7 files changed, 100 insertions(+), 27 deletions(-) diff --git a/src/AC/index.js b/src/AC/index.js index e3a996a..a6176de 100644 --- a/src/AC/index.js +++ b/src/AC/index.js @@ -1,6 +1,6 @@ import { INCREMENT, DELETE_ARTICLE, CHANGE_DATE_RANGE, CHANGE_SELECTION, ADD_COMMENT, LOAD_ALL_ARTICLES, LOAD_ARTICLE, - START, SUCCESS, FAIL + LOAD_COMMENTS, START, SUCCESS, FAIL } from '../constants' export function increment() { @@ -70,6 +70,25 @@ export function loadArticle(id) { payload: { id, response } })) - }, 1000) + }, 300) + } +} + +export function loadComments(id) { + return (dispatch) => { + dispatch({ + type: LOAD_COMMENTS + START, + payload: { id } + }) + + setTimeout(() => { + fetch(`/api/comment?article=${id}`) + .then(res => res.json()) + .then(response => dispatch({ + type: LOAD_COMMENTS + SUCCESS, + payload: { id, response } + })) + + }, 300) } } \ No newline at end of file diff --git a/src/components/Comment.js b/src/components/Comment.js index 4b123ce..27480f3 100644 --- a/src/components/Comment.js +++ b/src/components/Comment.js @@ -1,7 +1,7 @@ import React from 'react' import PropTypes from 'prop-types' import {connect} from 'react-redux' -import {createCommentSelector} from '../selectors' +import {commentSelector} from '../selectors' function Comment({comment}) { return ( @@ -20,13 +20,8 @@ Comment.propTypes = { }).isRequired } -const createMapStateToProps = () => { - const commentSelector = createCommentSelector() - return (state, ownProps) => { - return { - comment: commentSelector(state, ownProps) - } +export default connect((state, ownProps) => { + return { + comment: commentSelector(state, ownProps) } -} - -export default connect(createMapStateToProps)(Comment) \ No newline at end of file +})(Comment) \ No newline at end of file diff --git a/src/components/CommentList.js b/src/components/CommentList.js index 3082942..323c5d3 100644 --- a/src/components/CommentList.js +++ b/src/components/CommentList.js @@ -1,8 +1,12 @@ import React, {Component} from 'react' +import { connect } from 'react-redux' import PropTypes from 'prop-types' import CommentForm from './CommentForm' import Comment from './Comment' import toggleOpen from '../decorators/toggleOpen' +import Loader from './common/Loader' +import {loadComments} from '../AC' +import { commentsLoadingSelector, commentListSelector, commentsCacheSelector, commentsLoadedIdSelector } from '../selectors' class CommentList extends Component { static propTypes = { @@ -12,6 +16,11 @@ class CommentList extends Component { toggleOpen: PropTypes.func } + componentWillReceiveProps({ isOpen, article, loadComments }) { + //console.log('-', this.props); + if (!this.props.isOpen && isOpen && (this.props.loadedId != article.id)) loadComments(article.id) + } + render() { const {isOpen, toggleOpen} = this.props const text = isOpen ? 'hide comments' : 'show comments' @@ -24,12 +33,13 @@ class CommentList extends Component { } getBody() { - const {article: { comments, id }, isOpen} = this.props + const { comments, article: { id }, isOpen, loading} = this.props if (!isOpen) return null + if (loading) return const body = comments.length ? ( ) :

No comments yet

@@ -43,4 +53,11 @@ class CommentList extends Component { } -export default toggleOpen(CommentList) \ No newline at end of file +export default connect(state => { + return { + loading: commentsLoadingSelector(state), + comments: commentListSelector(state), + cache: commentsCacheSelector(state), + loadedId: commentsLoadedIdSelector(state) + } +}, {loadComments})(toggleOpen(CommentList)) \ No newline at end of file diff --git a/src/constants/index.js b/src/constants/index.js index f34f842..817345f 100644 --- a/src/constants/index.js +++ b/src/constants/index.js @@ -3,6 +3,7 @@ export const INCREMENT = 'INCREMENT' export const DELETE_ARTICLE = 'DELETE_ARTICLE' export const LOAD_ALL_ARTICLES = 'LOAD_ALL_ARTICLES' export const LOAD_ARTICLE = 'LOAD_ARTICLE' +export const LOAD_COMMENTS = 'LOAD_COMMENTS' export const CHANGE_SELECTION = 'CHANGE_SELECTION' export const CHANGE_DATE_RANGE = 'CHANGE_DATE_RANGE' diff --git a/src/middlewares/api.js b/src/middlewares/api.js index 52ed209..25ab7d1 100644 --- a/src/middlewares/api.js +++ b/src/middlewares/api.js @@ -16,5 +16,5 @@ export default store => next => action => { .then(res => res.json()) .then(response => next({...rest, response, type: type + SUCCESS})) .catch(error => next({...rest, error, type: type + FAIL})) - }, 1000) + }, 300) } \ No newline at end of file diff --git a/src/reducer/comments.js b/src/reducer/comments.js index 764e28c..3a9b686 100644 --- a/src/reducer/comments.js +++ b/src/reducer/comments.js @@ -1,16 +1,52 @@ -import { ADD_COMMENT } from '../constants' -import {normalizedComments} from '../fixtures' +import { Map, Record } from 'immutable' +import { ADD_COMMENT, LOAD_COMMENTS, START, SUCCESS, FAIL } from '../constants' import {arrToMap} from './utils' -export default (state = arrToMap(normalizedComments), action) => { - const { type, payload, randomId } = action +const CommentsRecord = Record({ + id: null, + user: null, + text: null +}) + +const ReducerRecord = Record({ + entities: arrToMap([], CommentsRecord), + loading: false, + loaded: false, + error: null, + //cache: false, + loadedId: null +}) + +export default (state = new ReducerRecord(), action) => { + const { type, payload, randomId, error } = action switch (type) { case ADD_COMMENT: - return state.set(randomId, { - ...payload.comment, - id: randomId - }) + return state.setIn(['entities', randomId], + new CommentsRecord({ ...payload.comment, id: randomId})) + + case LOAD_COMMENTS + START: + return state + .set('loading', true) + .set('loadedId', payload.id) + + case LOAD_COMMENTS + FAIL: + return state + .set('loading', false) + .set('error', error) + + case LOAD_COMMENTS + SUCCESS: + return state + .set('loading', false) + .set('loaded', true) + //.set('cache', true) + .set('entities', arrToMap(payload.response, CommentsRecord)) + + //case LOAD_ARTICLE + START: + // return articles.setIn(['entities', payload.id, 'loading'], true) + // + //case LOAD_ARTICLE + SUCCESS: + // return articles.setIn(['entities', payload.id], new ArticleRecord(payload.response)) } return state diff --git a/src/selectors/index.js b/src/selectors/index.js index c358756..b580605 100644 --- a/src/selectors/index.js +++ b/src/selectors/index.js @@ -3,7 +3,10 @@ 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 commentListMapSelector = state => state.comments.entities +export const commentsLoadingSelector = state => state.comments.loading +export const commentsLoadedIdSelector = state => state.comments.loadedId +export const commentsCacheSelector = state => state.comments.cache export const idSelector = (_, props) => props.id export const articlesSelector = createSelector(articlesMapSelector, articles => articles.valueSeq().toArray()) @@ -18,6 +21,8 @@ export const filtratedArticlesSelector = createSelector(articlesSelector, filter }) }) -export const createCommentSelector = () => createSelector(commentListSelector, idSelector, (comments, id) => { - return comments.get(id) +export const commentListSelector = createSelector(commentListMapSelector, comments => comments.valueSeq().toArray()) + +export const commentSelector = createSelector(commentListSelector, idSelector, (comments, id) => { + return comments.find(item => item.id == id) }) \ No newline at end of file From b50bc9fa095c6d586942821da939a1d0a91c898a Mon Sep 17 00:00:00 2001 From: AbilityG Date: Thu, 8 Feb 2018 01:34:16 +0600 Subject: [PATCH 2/3] Fix --- src/components/CommentList.js | 2 +- src/selectors/index.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/CommentList.js b/src/components/CommentList.js index 323c5d3..516e0e5 100644 --- a/src/components/CommentList.js +++ b/src/components/CommentList.js @@ -57,7 +57,7 @@ export default connect(state => { return { loading: commentsLoadingSelector(state), comments: commentListSelector(state), - cache: commentsCacheSelector(state), + //cache: commentsCacheSelector(state), loadedId: commentsLoadedIdSelector(state) } }, {loadComments})(toggleOpen(CommentList)) \ No newline at end of file diff --git a/src/selectors/index.js b/src/selectors/index.js index b580605..e5cd983 100644 --- a/src/selectors/index.js +++ b/src/selectors/index.js @@ -6,7 +6,7 @@ export const filtersSelector = state => state.filters export const commentListMapSelector = state => state.comments.entities export const commentsLoadingSelector = state => state.comments.loading export const commentsLoadedIdSelector = state => state.comments.loadedId -export const commentsCacheSelector = state => state.comments.cache +//export const commentsCacheSelector = state => state.comments.cache export const idSelector = (_, props) => props.id export const articlesSelector = createSelector(articlesMapSelector, articles => articles.valueSeq().toArray()) From 9d41b55cd90da833def8d79f54693f4c2229b40f Mon Sep 17 00:00:00 2001 From: AbilityG Date: Thu, 8 Feb 2018 01:35:09 +0600 Subject: [PATCH 3/3] Fix --- src/reducer/comments.js | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/reducer/comments.js b/src/reducer/comments.js index 3a9b686..e5c3901 100644 --- a/src/reducer/comments.js +++ b/src/reducer/comments.js @@ -41,12 +41,6 @@ export default (state = new ReducerRecord(), action) => { .set('loaded', true) //.set('cache', true) .set('entities', arrToMap(payload.response, CommentsRecord)) - - //case LOAD_ARTICLE + START: - // return articles.setIn(['entities', payload.id, 'loading'], true) - // - //case LOAD_ARTICLE + SUCCESS: - // return articles.setIn(['entities', payload.id], new ArticleRecord(payload.response)) } return state