How can a child component force its parent to reload? React.js

Viewed 1306

TLTR: I want the child component to be able to refresh the entire parent component and it's own child components so that they make their initial http requests in their own componentDidMount functions. I tried to setState {...prevState} in the parent component when the function given in props is called, but it doesn't trigger the http requests in the componentDidMount of the children, and I don't even think that it causes any re render. I also tried this.forceUpdate() but that didn't work either.

I have a parent component called LikesCommentsNumbers where I put the child components Like, Like (prop: dislike) and comment. Each one of them manages its own state and makes a HTTP request to get the number of likes and if the like icon should be filled (which means that the user has already liked something).

Upon pressing the like/dislike a HTTP call is issued where the count of likes is incremented and the count of dislikes is decremented (if the user pressed the like button, and the other way around if he pressed the dislike button).

My point is, how to do the clean up?

When the user presses the like/dislike button I want the component to force the whole parent component to refresh / call for the data again. I tried to do it in many ways, trying to execute a function in the child component given in the props by the parent, that would make the parent component setState {...prevState} and hopefully refresh also all of the children, but it didn't work. This.forceUpdate also didn't work. How can I make all the childrens' componentDidMount() [in which are my http requests] function to run again?

My component structure:

[![enter image description here][1]][1]

LikesCommentsNumbers:


import axios from 'axios';

import { FaCommentAlt } from 'react-icons/fa';
import Like from '../UI/like';

import classes from './likesCommentsNumbers.module.css';
import getToken from '../../getToken';

class LikesCommentsNumbers extends Component {
    constructor(props){
        super(props);

        let token = getToken();

        this.state = {
            objectId: props.objectId,
            userId: props.userId,
            token: token,
            numberOfComments: 0,
            LikeRefresh: false,
            DislikeRefresh: false,
        }
        this.actionCleanUp.bind(this);
    }

    componentDidMount() {
        if(this.props.comments){
            axios({
                method: 'post',
                url: "http://localhost:3001/comments/getNumber",
                headers: {'Authorization': this.state.token},
                data: {
                    blogId: this.state.objectId
                }
            })
            .then((res)=>{
                if(res.status===200){
                    this.setState({numberOfComments: res.data.count});
                    return;
                }
            })
            .catch(error => {
                console.log(error);
            })
        }
    }

    actionCleanUp = (type) => {
        this.setState((prevState) => {
            return ({...prevState});
        })
    }

    render() { 
        let commentIcon = null;
        if(this.props.comments){
            commentIcon = (
                <div className={classes.iconDataContainer}>
                        <FaCommentAlt size="1em" color="#0a42a4" className={classes.icon}/>
                        <p>{this.state.numberOfComments}</p>
                    </div>
            )
        }
        let dislikeclasses = classes.iconDataContainer;
        if(!this.props.comments){
            dislikeclasses = [classes.iconDataContainer, classes.movetoleft].join(" ")
        }

        let innerContainer = classes.numberInfoInnerContainer;
        if(this.props.small){
            innerContainer = [classes.numberInfoInnerContainer, classes.small].join(" ");
        }

        return (
            <div className={classes.numberInfoContainer}>
                <div className={innerContainer}>
                    <div className={[classes.iconDataContainer, classes.likeIconPContainer].join(" ")}>
                        <Like
                            refresh={this.state.LikeRefresh} 
                            objectIsBlog={this.props.objectIsBlog} 
                            token={this.state.token} 
                            authorId={this.state.userId} 
                            objectId={this.state.objectId} 
                            cleanUp={this.actionCleanUp}
                            size="1.5em" 
                            color="#0a42a4" 
                            className={classes.icon}/>
                    </div>
                    <div className={dislikeclasses}>
                        <Like
                            refresh={this.state.DislikeRefresh} 
                            dislike 
                            objectIsBlog={this.props.objectIsBlog} 
                            token={this.state.token} 
                            authorId={this.state.userId} 
                            objectId={this.state.objectId} 
                            cleanUp={this.actionCleanUp}
                            size="1.5em" 
                            color="#0a42a4" 
                            className={classes.icon}/>
                    </div>
                    {commentIcon}
                </div>
            </div>
        );
    }
}
 
export default LikesCommentsNumbers;```


Like.js:


//componentDidMount:
componentDidMount(){
        this.getData(); //http request to get number
        this.handleFill(); //http request to check if liked already
    }
//sendAction function: 

 sendAction = (like) => {
        if(this.props.objectIsBlog){
            let url = "http://localhost:3001/blogLike/upvote";
            if(this.props.dislike) url = "http://localhost:3001/blogLike/downvote";    
            axios({
                method: 'post',
                url: url,
                headers: {'Authorization': this.state.token},
                data: { blogId: this.state.objectId }
            })
            .then((res)=>{
                if(res.status===201 || res.status===200){
                    if(like){
                        this.props.cleanUp("like");
                    }
                    else {
                        this.props.cleanUp("dislike");
                    }
                }
                // this.setState({redirect: true})
                // window.location.reload();
                this.props.cleanUp();
            })
            .catch(error => {
                console.log(error);
            })
        }
        else{
            let url = "http://localhost:3001/commentLike/upvote";
            if(this.props.dislike) url = "http://localhost:3001/commentLike/downvote";
    
            axios({
                method: 'post',
                url: url,
                headers: {'Authorization': this.state.token},
                data: { commentId: this.state.objectId }
            })
            .then((res)=>{
                if(res.status===200){
                    this.setState((prevState) => {
                        return ({
                            ...prevState,
                            number: res.data.count
                        })
                    })
                }
            })
            .catch(error => {
                console.log(error);
            })
        }
    }

//render function:
let content;
    
        if(this.props.dislike && this.state.DislikeFill){
            content = <AiFillDislike 
            size={this.props.size} 
            color={this.props.color} 
            onClick={() => this.sendAction(false)}/>;
        }
        else if(this.props.dislike && !this.state.DislikeFill){
            content = <AiOutlineDislike 
            size={this.props.size} 
            color={this.props.color} 
            onClick={() => this.sendAction(false)}/>;
        }
        else if(this.state.LikeFill){
            content = <AiFillLike 
            size={this.props.size} 
            color={this.props.color} 
            onClick={() => this.sendAction(true)}/>;
        }
        else if(!this.state.LikeFill){
            content = <AiOutlineLike 
            size={this.props.size} 
            color={this.props.color} 
            onClick={() => this.sendAction(true)}/>;
        }

        return (
            <div className={classes.likeContainer}>
                {content}
                <p className={classes.likeP}>{this.state.number}</p>
            </div>
        );



  [1]: https://i.stack.imgur.com/xjk3G.png
1 Answers

create a new function in the parent component :

updateFromChild(){this.setState({//update whatever state you want}).

Then when rendering the child component pass that function :

Like refresh={this.state.LikeRefresh} objectIsBlog={this.props.objectIsBlog} ... updateFromChild={this.updateFromChild}/>

In the child component when the like is hit or whenever u want to update the parent use

this.props.updateFromChild() and it will update the whole parent component.

Related