From f0c9f73f94b2304ad3745c3070d36ba572bcd9f3 Mon Sep 17 00:00:00 2001 From: Denis Komyagin Date: Wed, 14 Mar 2018 21:36:29 +0300 Subject: [PATCH] homework 5 done --- src/AC/index.js | 26 +++++++++++++++++++++++++- src/components/comment-list/index.js | 16 ++++++++++++++-- src/components/comment.js | 3 ++- src/constants/index.js | 1 + src/reducer/articles.js | 8 +++++--- src/reducer/comments.js | 24 ++++++++++++++++++++++-- src/selectors/index.js | 3 ++- 7 files changed, 71 insertions(+), 10 deletions(-) diff --git a/src/AC/index.js b/src/AC/index.js index 401b5b1..b035b7d 100644 --- a/src/AC/index.js +++ b/src/AC/index.js @@ -1,5 +1,5 @@ import { - INCREMENT, DELETE_ARTICLE, CHANGE_DATE_RANGE, CHANGE_SELECTION, ADD_COMMENT, LOAD_ALL_ARTICLES, LOAD_ARTICLE, + LOAD_COMMENTS, INCREMENT, DELETE_ARTICLE, CHANGE_DATE_RANGE, CHANGE_SELECTION, ADD_COMMENT, LOAD_ALL_ARTICLES, LOAD_ARTICLE, START, SUCCESS, FAIL } from '../constants' @@ -74,4 +74,28 @@ export function loadArticleById(id) { })) }, 1000) } +} + +export function loadCommentsForArticle(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} + })) + .catch(error => dispatch({ + type: LOAD_COMMENTS + FAIL, + payload: {id, error} + })) + },1000) + } + } \ No newline at end of file diff --git a/src/components/comment-list/index.js b/src/components/comment-list/index.js index 173cb68..47e964c 100644 --- a/src/components/comment-list/index.js +++ b/src/components/comment-list/index.js @@ -5,6 +5,10 @@ import Comment from '../comment' import CommentForm from '../comment-form' import toggleOpen from '../../decorators/toggleOpen' import './style.css' +import {loadCommentsForArticle} from "../../AC/index"; +import {connect} from "react-redux"; +import {loadingCommentsSelector} from "../../selectors/index"; +import Loader from "../loader"; class CommentList extends Component { static defaultProps = { @@ -18,6 +22,10 @@ class CommentList extends Component { toggleOpen: PropTypes.func } + componentWillReceiveProps({ isOpen, loadCommentsForArticle, article }) { + if (!this.props.isOpen && isOpen && !article.commentsLoaded) loadCommentsForArticle(article.id) + } + render() { const {isOpen, toggleOpen} = this.props const text = isOpen ? 'hide comments' : 'show comments' @@ -36,8 +44,9 @@ class CommentList extends Component { } getBody() { - const {article: { comments, id }, isOpen} = this.props + const {article: { comments, id,commentsLoaded }, loading,isOpen} = this.props if (!isOpen) return null + if(loading&&!commentsLoaded) return return (
@@ -66,4 +75,7 @@ class CommentList extends Component { } -export default toggleOpen(CommentList) \ No newline at end of file + +export default connect(state=>({ + loading:loadingCommentsSelector(state) +}),{loadCommentsForArticle})(toggleOpen(CommentList)) \ No newline at end of file diff --git a/src/components/comment.js b/src/components/comment.js index dba04b4..48afbfb 100644 --- a/src/components/comment.js +++ b/src/components/comment.js @@ -4,6 +4,7 @@ import { connect } from 'react-redux' import { createCommentSelector } from '../selectors' function Comment({comment}) { + if(!comment) return null; return (
{comment.text} by {comment.user} @@ -15,7 +16,7 @@ Comment.propTypes = { comment: PropTypes.shape({ text: PropTypes.string.isRequired, user: PropTypes.string - }).isRequired + }) } const createMapStateToProps = () => { diff --git a/src/constants/index.js b/src/constants/index.js index f34f842..8a18b45 100644 --- a/src/constants/index.js +++ b/src/constants/index.js @@ -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' diff --git a/src/reducer/articles.js b/src/reducer/articles.js index 26166cc..a51a0cf 100644 --- a/src/reducer/articles.js +++ b/src/reducer/articles.js @@ -1,4 +1,4 @@ -import { DELETE_ARTICLE, ADD_COMMENT, LOAD_ALL_ARTICLES, LOAD_ARTICLE, START, SUCCESS, FAIL } from '../constants' +import { LOAD_COMMENTS, DELETE_ARTICLE, ADD_COMMENT, LOAD_ALL_ARTICLES, LOAD_ARTICLE, START, SUCCESS, FAIL } from '../constants' import { arrToMap } from './utils' import { Record } from 'immutable' @@ -8,7 +8,8 @@ const ArticleRecord = Record({ text: null, date: null, loading: false, - comments: [] + comments: [], + commentsLoaded:false }) const ReducerState = Record({ @@ -45,7 +46,8 @@ export default (articles = new ReducerState(), action) => { case LOAD_ARTICLE + SUCCESS: return articles.setIn(['entities', payload.id], new ArticleRecord(payload.response)) - + case LOAD_COMMENTS + SUCCESS: + return articles.setIn(['entities',payload.id,'commentsLoaded'],true) default: return articles diff --git a/src/reducer/comments.js b/src/reducer/comments.js index 9f32503..fa8fc1b 100644 --- a/src/reducer/comments.js +++ b/src/reducer/comments.js @@ -1,8 +1,22 @@ import { ADD_COMMENT } from '../constants' -import {normalizedComments} from '../fixtures' import {arrToMap} from './utils' +import { Record } from 'immutable' +import {LOAD_COMMENTS, START, SUCCESS} from "../constants/index"; -export default (state = arrToMap(normalizedComments), action) => { +const CommentRecord = Record({ + id: null, + user: null, + text: null, +}) + +const ReducerState = Record({ + entities: arrToMap([], CommentRecord), + loading: false, + loaded: false, + error: null +}) + +export default (state = new ReducerState(), action) => { const { type, payload, randomId } = action switch (type) { @@ -11,7 +25,13 @@ export default (state = arrToMap(normalizedComments), action) => { ...payload.comment, id: randomId }) + case LOAD_COMMENTS + START: + return state.set("loading",true) + case LOAD_COMMENTS + SUCCESS: + return state.update("entities",comments=>comments.merge(arrToMap(payload.response,CommentRecord))) + .set("loading",false) + .set("loaded",true) default: return state } diff --git a/src/selectors/index.js b/src/selectors/index.js index 0f58db6..aafc319 100644 --- a/src/selectors/index.js +++ b/src/selectors/index.js @@ -3,8 +3,9 @@ import { createSelector } from 'reselect' export const articlesMapSelector = state => state.articles.entities export const articleListSelector = createSelector(articlesMapSelector, articlesMap => articlesMap.valueSeq().toArray()) export const loadingArticlesSelector = state => state.articles.loading +export const loadingCommentsSelector = state => state.comments.loading -const commentsSelector = state => state.comments +const commentsSelector = state => state.comments.entities const filtersSelector = state => state.filters const idSelector = (_, props) => props.id