Amber Wallen
Amber Wallen

Reputation: 57

onClick function fires after clicking twice

For some reason, the onClick will not fire once, but if clicked twice. The this.props.PostLike(id) action will be fired, What should i do to make it work only on one click.

Also, the heart state works fine, in just one click. Its just the this.props.postLike needs to be clicked twice for it work.

And using e.preventDefault() does not solve the issue.

    ....
    clickLike = (id) => {
        this.props.postLike(id);
        // toggles between css class
        this.setState({
            heart: !this.state.heart
        })
    }
    render(){
       return(
            <div style={{float:'right', fontSize: '1.5em', color:'tomato'}} >
            <i style={{ marginRight: '140px'}} className={this.state.heart ? 'fa fa-heart':'fa fa-heart-o' }>
                    <span style={{ marginLeft: '6px'}}>
                        <a href="#" onClick={() =>this.clickLike(this.props.like)}>Like</a>   

                    </span>
                    {/* gets the like counts */}
                    <span style={{ marginLeft: '7px'}} >{this.props.likes}  </span>  

                </i>
            </div>       
       )
    }
}
const mapStateToProps = (state) => ({

})
const mapDispatchToProps = (dispatch) => ({

    postLike: (id) => dispatch( postLike(id))
    // Pass id to the DeletePost functions.
});
export default connect(null, mapDispatchToProps)(Like);

PostItem.js

import React, { Component } from 'react';
import Paper from '@material-ui/core/Paper';
import Button from '@material-ui/core/Button';
import Typography from '@material-ui/core/Typography';
import moment from 'moment';
import Editable from './Editable';
import {connect} from 'react-redux';
import {UpdatePost, postLike, getCount} from '../actions/';
import Like from './Like';
import Axios from '../Axios';
const Styles = {
    myPaper: {
        margin: '20px 0px',
        padding: '20px'
    },
    button:{
        marginRight:'30px'
    }
}
class PostItem extends Component{
    constructor(props){
        super(props);
        this.state = {
            disabled: false,
            myId: 0,
            likes:0
        }
    }


    onUpdate = (id, title) => () => {
        // we need the id so expres knows what post to update, and the title being that only editing the title. 
        if(this.props.myTitle !== null){
            const creds = {
                id, title
            }
            this.props.UpdatePost(creds); 
        }
    }

    render(){
        const {title, id, userId, removePost, createdAt, post_content, username, editForm, isEditing, editChange, myTitle, postUpdate, Likes, clickLike, myLikes} = this.props
        return(
                  ......
                      {/* likes get like counts */}
                       <Like like={id} likes={myLikes} />
                  .......

Posts.js

render() {
        const {loading} = this.state;
        const {myPosts} = this.props
        console.log(this.state.posts);
        if (!this.props.isAuthenticated) {
            return (<Redirect to='/signIn'/>);
        }
        if (loading) {
            return "loading..."
        }
        return (
            <div className="App" style={Styles.wrapper}>
                <h1>Posts</h1>
                {/* <PostList posts={this.state.posts}/> */}
                <div>
                    {this.state.posts.map(post => (
                            <Paper key={post.id} style={Styles.myPaper}>
                                <PostItem myLikes={post.Likes.length} // right here
                                    myTitle={this.state.title} editChange={this.onChange} editForm={this.formEditing} isEditing={this.props.isEditingId === post.id} removePost={this.removePost} {...post}/>
                            </Paper>
                        ))}
                </div>
            </div>
        );
    }
}

PostList.js

import React, { Component } from 'react';
import Paper from '@material-ui/core/Paper';
import Button from '@material-ui/core/Button';
import Typography from '@material-ui/core/Typography';
import moment from 'moment';
import {connect} from 'react-redux';
import { withRouter, Redirect} from 'react-router-dom';
import {DeletePost, postLike, UpdatePost,EditChange, GetPosts, getCount, DisableButton} from '../actions/';
import PostItem from './PostItem';
import _ from 'lodash';
const Styles = {
    myPaper: {
        margin: '20px 0px',
        padding: '20px'
    }
}
class PostList extends Component{
    constructor(props){
        super(props);
        this.state ={
            title: '',
            posts:[],
            loading:true

        }
    } 

    componentWillMount() {
        this.props.GetPosts();
    }
    componentWillReceiveProps(nextProps, prevState) {
        let hasNewLike = true;
        if (prevState.posts && prevState.posts.length) {
            for (let index = 0; index < nextProps.myPosts.length; index++) {
                if (nextProps.myPosts[index].Likes.length !== prevState.posts[index].Likes.length) {
                    hasNewLike = true;
                }
            }
        }
        if (hasNewLike) {
            this.setState({posts: nextProps.myPosts, loading: false}); // here we are updating the posts state if redux state has updated value of likes
        }
    }
    // Return a new function. Otherwise the DeletePost action will be dispatch each
     // time the Component rerenders.
    removePost = (id) => () => {
        this.props.DeletePost(id);
    }

    onChange = (e) => {
        e.preventDefault();
        this.setState({
            title: e.target.value
        })
    }
    formEditing = (id) => ()=> {;
        this.props.EditChange(id);
    }
    render(){
        const { posts, loading} = this.state;

        // console.log(this.props.posts)
        // console.log(this.props.ourLikes);
        if(loading){
            return "loading..."
        }
        return (
          <div>
            {this.state.posts.map(post => (

              <Paper key={post.id} style={Styles.myPaper}>
                <PostItem
                  myLikes={post.Likes.length} // right here
                  myTitle={this.state.title}
                  editChange={this.onChange}
                  editForm={this.formEditing}
                  isEditing={this.props.isEditingId === post.id}
                  removePost={this.removePost}
                  {...post}

                />
              </Paper>
            ))}
          </div>
        );
    }
}
const mapStateToProps = (state) => ({
    isEditingId: state.post.isEditingId,
    myPosts: state.post.posts, 
})
const mapDispatchToProps = (dispatch) => ({
    // pass creds which can be called anything, but i just call it credentials but it should be called something more 
    // specific.
    GetPosts: () => dispatch(GetPosts()),
    EditChange: (id) => dispatch(EditChange(id)),
    UpdatePost: (creds) => dispatch(UpdatePost(creds)),
    postLike: (id) => dispatch( postLike(id)),
    // Pass id to the DeletePost functions.
    DeletePost: (id) => dispatch(DeletePost(id))
});
// without withRouter componentWillReceiveProps will not work like its supposed too.
export default withRouter(connect(mapStateToProps,mapDispatchToProps)(PostList));

Upvotes: 1

Views: 655

Answers (4)

Kishan Jaiswal
Kishan Jaiswal

Reputation: 664

 clickLike = async(id) => {
    await this.props.postLike(id);
    // toggles between css class
    this.setState({
        heart: !this.state.heart
    })
 }

try using the async await

  <span style={{ marginLeft: '6px'}} onClick= 
         {()=>this.clickLike(this.props.like)}>
       <a href="#" >Like</a>   
   </span>

Upvotes: 0

Jo&#227;o Victor
Jo&#227;o Victor

Reputation: 639

Try doing like that:

clickLike = (id) => () => {
    this.props.postLike(id);
    // toggles between css class
    this.setState({
        heart: !this.state.heart
    })
}
<a href="#" onClick={this.clickLike(this.props.like)}>Like</a>

Upvotes: 1

ndinnar
ndinnar

Reputation: 35

You have to be careful when using arrow functions with the this keyword as it does not refer to the current object, but its parent object instead.

Upvotes: 0

Cat_Enthusiast
Cat_Enthusiast

Reputation: 15688

This likely has little to do with the logic you have set up and more about the html markup itself. If you were to take in the event and console.log it, you'll probably find that you are actually not hitting the tag on the first click, but one of its outer elements. Try wrapping the tag and everything else inside of it in a tag then putting the onClick logic in the button instead and you'll yield better results.

     <div style={{float:'right', fontSize: '1.5em', color:'tomato'}} >
        <button onClick={() =>this.clickLike(this.props.like)}>
            <i style={{ marginRight: '140px'}} className={this.state.heart ? 'fa fa-heart':'fa fa-heart-o' }>
                <span style={{ marginLeft: '6px'}}>
                    <a href="#">Like</a>   

                </span>
                {/* gets the like counts */}
                <span style={{ marginLeft: '7px'}} >{this.props.likes}  </span>  

            </i>
          </button>
       div>   

Upvotes: 1

Related Questions