Home > Software design >  How can I re-render one component from another component in React?
How can I re-render one component from another component in React?

Time:05-22

I have one component with a form that creates posts and then I have another component that displays these posts in a feed. How do I get the feed to re-render when a new post is created? What's the best way to do that?

  1. Re-render the parent component without changing props?
  2. Update props?
  3. Some other way?

Create.js

import React, { useState } from "react";

export default function Create () {
    const [form, setForm] = useState({
      post: "",
    });

    // These methods will update the state properties.
    function updateForm(value) {
        return setForm((prev) => {
        return { ...prev, ...value };
        });
  }

  async function onSubmit(e) {
      e.preventDefault();

    // When a post request is sent to the create url, we'll add a new post to the database.
    const newPost = { ...form };

    await fetch("http://localhost:3000/post/add", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify(newPost),
      })
      .catch(error => {
        window.alert(error);
        return;
      });
  
      setForm({ post: "" });
  }

  

  return (
      <div>
        <form onSubmit={onSubmit}>
            <div className="form-group">
            <label htmlFor="post">Post</label>
            <input
                type="text"
                className="form-control"
                id="post"
                value={form.post}
                onChange={(e) => updateForm( { post: e.target.value })}
            />
            </div>
            <div className="form-group">
            <input
                type="submit"
                value="Create post"
                className="btn btn-primary"
            />
            </div>
          </form>
        </div>
    );
}

Feed.js

import React, { useEffect, useState } from "react";
import { Link } from "react-router-dom";

const Post = (props) => (
    <div>
        {props.post.post}
            <Link className="btn btn-link" to={`/edit/${props.post._id}`}>Edit</Link>
              <button className="btn btn-link" onClick={() => { props.deletePost(props.post._id);
            }}
            >
        Delete
      </button>
    </div>
);

export default function PostList() {
    const [posts, setPosts] = useState([]);
  
    // This method fetches the posts from the database.
    useEffect(() => {
      async function getPosts() {
        const response = await fetch(`http://localhost:3000/post/`);
  
        if (!response.ok) {
          const message = `An error occured: ${response.statusText}`;
          window.alert(message);
          return;
        }
  
        const posts = await response.json();
        setPosts(posts);
      }
  
      getPosts();
  
      return; 
    }, [posts.length]);
  
    // This method will delete a post
    async function deletePost(id) {
      await fetch(`http://localhost:3000/${id}`, {
        method: "DELETE"
      });
  
      const newPosts = posts.filter((el) => el._id !== id);
      setPosts(newPosts);
    }
  
    // This method will map out the posts on the table
    function postList() {
      return posts.map((post) => {
        return (
          <Post
            post={post}
            deletePost={() => deletePost(post._id)}
            key={post._id}
          />
        );
      });
    }
  
    // This following section will display the the posts.

    return (
      <div>
        <h3>Post List</h3>
        <div>{postList()}</div>
      </div>
    );
  }

Home.js

import React from "react";
import Feed from "./feed";
import Create from "./create";


const Home = () => {  

  return (
    <div className="app">
      <div>
        <Create />
        <Feed />
      </div>
    </div>
  );
};

export default Home;

CodePudding user response:

There are numerous ways to do so. The one you should start with is the most straightforward: pass your current posts and setPosts into both component from a parent component:

const Parent = () => {
  const [posts, setPosts] = useState([]);
  return <>
    <Create posts={posts} setPosts={setPosts} />
    <PostList posts={posts} setPosts={setPosts} />
  </>
}

There are better ways to do so, but they are more involved. I suggest you to start with this one to understand how React handles data better.

  • Related