0

I am trying to add a like increment count using redux to my app, but I am not what I have to do I have been tampering with it for the last few days and have gotten nowhere. I wanted to use my comments from my shared folder as the state that I wanted to alter on the store. Any help would be appreciated! Thanks

this is my store:

import { createStore, combineReducers } from 'redux';
import { Comments } from './comments';
import { counterReducer } from './counter'

export const ConfigureStore = () => {
const store = createStore(
    combineReducers({
        counter : counterReducer,
        comments: Comments
    }
));

return store;
};

action creators:

import * as ActionTypes from './ActionTypes';

export const addComment = (commentId, author, text, likes, date) => ({
type: ActionTypes.ADD_COMMENT,
payload: {
    commentId : commentId,
    author: author,
    text: text,
    likes: likes,
    date: date
}
});

export const likeComment = (commentId, likes) => ({
type: ActionTypes.LIKE_COMMENT,
payload: {
    commentId: commentId,
    likes: likes
}
 });

my counter reducer for the likes (i am using my COMMENTS as my state that has the commentId, comments, author, dates, likes):

import * as ActionTypes from './ActionTypes';
import { COMMENTS } from '../shared/comments';


export const counterReducer = (state = COMMENTS, action) => {
switch(action.type) {
    case ActionTypes.LIKE_COMMENT:
        const comment = action.payload
        comment.id = state.length 
        comment.like = state.likes + 1
        return state.concat(comment)
    default:
        return state;
}
};

This is the main component:

import React, { Component } from 'react';
import TopComment from './TopComment';
import DisplayComment from './PostComment';
import { withRouter } from 'react-router-dom';
import { connect } from 'react-redux';
import { addComment, likeComment } from '../redux/ActionCreators';

const mapStateToProps = state => {
return {
    comments: state.comments,
    likes: state.likes
}
};

const mapDispatchToProps = {
addComment: (commentId, author, text, likes, date) => (addComment(commentId, author, text, 
likes, date)),
likeComment: (likes) => (likeComment(likes))
  }

class Main extends Component{
render(){
    return(
        <div className="comment-box">
            <h1>Join the discussion!</h1>
            <h1>Adam's post:</h1>
            <TopComment/>
            <DisplayComment
            addComment = {this.props.addComment}
            likeComment ={this.props.likeComment}
            comments = {this.props.comments}
            />
        </div>
    )
   }
   }

   export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Main));

post comment component that will add and display each comment that has been entered through the input:

import React, { Component } from 'react';
import { Button, Card, CardBody, CardTitle, CardText } from 'reactstrap';
import { Control, LocalForm, Errors} from 'react-redux-form';

// will check validation
const required = val => val && val.length;
const maxLength = len => val => !val || (val.length <= len);
const minLength = len => val => val && (val.length >= len);



// will display comment when posted
function RenderComments({comments}) {

 function handleLike(){
    this.props.likeComment(this.props.likeComment)
 }

 if (comments) {
    return (
        <div className="col-sm-12">
            <h4>Comments</h4>
                {
                    comments.map(comment => {
                        return (
                            <div className="container">
                            <div className="row">
                                <div className="col-sm-12 ">
                                    <Card style={{ 
                                        backgroundColor: '#212d40',
                                        borderColor: '#fff',
                                        borderRadius: '0.25rem',
                                        padding: '0.5rem 0.5rem 0.5rem',
                                        marginBottom: '20px'
                                        }}>
                                        <CardBody>
                                            <img src="./images/random.jpeg" alt="random" height="50px" />
                                            <CardTitle tag="h3">{comment.author}</CardTitle>
                                            <CardText>{comment.text}, <br/>
                                            likes: {comment.likes} <br/>
                                            {new Intl.DateTimeFormat('en-US', { year: 'numeric', month: 'short', day: '2-digit'}).format(new Date(Date.parse(comment.date)))}
                                            </CardText> <br/>
                                            <Button onClick={handleLike}>Like </Button>
                                        </CardBody>
                                    </Card>
                                </div>
                            </div>
                        </div>
                        );
                    })
                }
        </div>
    );
}
return <div/>;
}

class PostComment extends Component {

handleSubmit(values) {
    this.props.addComment(this.props.commentId, values.author, values.text, values.date);
}

render(){
    return(
        <div>
            <LocalForm className="comment-form" onSubmit={ values => 
      this.handleSubmit(values) }>
                <div className="form-group">
                    <Control.text
                    model=".author"
                    className="form-control" 
                    placeholder="name" 
                    validators={{
                        required, 
                        minLength: minLength(2),
                        maxLength: maxLength(15)
                    }}
                    />
                    <Errors
                    className="text-danger"
                    model=".author"
                    show="touched"
                    component="div"
                    messages={{
                        required: 'Required',
                        minLength: 'Must be at least 2 characters',
                        maxLength: 'Must be 15 characters or less'
                    }}
                    />
                </div>
                <div className="form-group">
                    <Control.text
                    model=".text"
                    className="form-control"
                    placeholder="comment" 
                    />
                </div>
                <Button className="btn-color"  color="primary" type="submit">Submit</Button>
            </LocalForm>
        </div>
    )
}
}

function DisplayComment(props){
 return(
    <div>
        <div className="col">
        <RenderComments 
        addComment = {props.addComment}
        deleteComment =  {props.deleteComment}
        comments = {props.comments}
        likeComment = {props.likeComment}
        />
        </div>
        <div className="col">
        <PostComment
        addComment = {props.addComment}
        comments = {props.comments}
        likeComment= {props.likeComment}
        />
        </div>
    </div>
  )
  }

   export default DisplayComment

this is my commments from my shared file that has all the comment data (likes, comment, date, etc):

export const COMMENTS = [
{
    commentId: 0,
    author: 'Richard',
    text: 'I love disum!',
    likes: 1,
    date: "2020-07-01T19:44Z"
},
{
    commentId: 1,
    author: 'Jake Paul',
    text: 'Fried foods are the best!',
    likes:  0,
    date: "2020-09-20T19:44Z"
}
]
  • Step 1 - install and configure [redux dev tools](https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd?hl=en) – Adam Feb 10 '21 at 02:07
  • `comment.like = state.likes + 1` looks weird... where is like count actually stored, in each comment or one count for all comments? – Dima Tisnek Feb 10 '21 at 02:10
  • @DimaTisnek I was looking store the likes for each comment. Can that be done on redux? – dmarceo316 Feb 10 '21 at 02:12
  • @dmarceo316 - as pointed out in my answer, but putting the `likes` count in each comment entity, your confusing the source of truth for the number of likes on a given comment. What do you want to do - just store the number of likes? Or store meta information about a like - when it was created, who it was created by, etc? If you want to store meta information about a like, then get rid of the `likes` property of your comment object. – Adam Feb 10 '21 at 02:15
  • Ahh now I see what you were trying to do. **Bye default**, the two combined reducers are **independent**, one reducer cannot see the state in the other reducer. But you are trying to peek at the other reducer. There's a way to do that, if you really need it. – Dima Tisnek Feb 10 '21 at 02:16
  • Does this answer your question? [Accessing a part of reducer state from one reducer within another reducer](https://stackoverflow.com/questions/42239302/accessing-a-part-of-reducer-state-from-one-reducer-within-another-reducer) – Dima Tisnek Feb 10 '21 at 02:18
  • https://stackoverflow.com/questions/42239302/accessing-a-part-of-reducer-state-from-one-reducer-within-another-reducer – Dima Tisnek Feb 10 '21 at 02:18
  • @Adam I was looking to start each comment off with 0, But I was only looking to increment an individual comment likes. I'm hoping that makes sense. I am a little new to redux and trying to piece everything together. – dmarceo316 Feb 10 '21 at 02:33
  • @dmarceo316 - If you have a counter reducer where you store all your likes, then a comment's likes are [derived data](https://redux.js.org/recipes/computing-derived-data). A comment only has likes it there are entries in the likes reducer, otherwise, it has zero likes. Alternatively, as I illustrated in my answer below, you can just store everything together and modify your `comments` reducer to increment the number of likes. – Adam Feb 10 '21 at 02:38

1 Answers1

1

You're mixing the source of truth for comment likes. Should the likes count be part of the comment? Or should it be it's own thing?

Let's KISS and just keep the likes count as part of the comment as you have already set up - get rid of your other counter reducer altogether.

Your comments reducer should now look like this:

  switch(action.type) {
    case ActionTypes.ADD_COMMENT:
        // your existing code to handle adding a comment to your state

    // this new case increments the likes for a given comment
    case ActionTypes.LIKE_COMMENT:
        return state.comments.map(c => c.commentId === action.payload.commentId ? ({ ...c,likes: c.likes+1 }) : c);
    default:
        return state;
  }
};
Adam
  • 41,349
  • 10
  • 58
  • 78