Search code examples
reactjsuse-effectuse-statereact-functional-component

ReactJS - How to re-render functional component after POST data to database


I am building a blogging application. This application has frontend built with ReactJS and backend built with Python (Django Framework). The frontend and backend are connected with Django REST API Framework.

This post is on ReactJS Frontend.

I am using Functional Component. There is a "BlogList" Component where all blogs fetched from API endpoints will be displayed. I created a "BlogForm" Component where I have to enter 2 fields: "Title" and "Content" to create blog post. I imported the "BlogForm" Component inside "BlogList" Component to show it on the same page. Please see this image to get a good understanding

When I enter "Title" and "Content" inside "BlogForm" Component and click on "Submit" button, data is saved in database using API call. But the added data is not showing in the "BlogList" Component at that time. I have to refresh the page to see the new blog post in the blog list.

Can anyone in the community help me to solve the problem that how can I instantly view the added blog post when I click on "Submit" button?

For your kind reference, the code is as below.

BlogList.js

import BlogForm from './BlogForm'

const BlogList = (url) => {

    
    const [blogs, setBlogs] = useState([])

    useEffect(() => {
        
        async function fetchBlogData() {
            
            const url = requests.blogList

            const request = await axios.get(url)

            setBlogs(request.data)
            return request
        }
        fetchBlogData()
    }, [url])

    return (
        <Wrapper>
            <BlogWrapper className="blog">

                // Blog Form Component Added
                <BlogForm />

                <div className="blog__header">
                    <h1 className="blog__header--title">
                        Information
                    </h1>
                </div>
                <hr className="blog__divider"/>
                <div className="blog__list">
                    <ul>
                        <li className="blog__item">
                            { blogs.map( (blog) => (
                                <div className="blog__item--container" key={ blog.id }>
                                    <h1 className="blog__item--title">
                                        <a className="blog__item--title blog__item--title--link" href={`/blog/${ blog.id }`}>
                                            { blog.title }
                                        </a>
                                    </h1>
                                    <small className="blog__item--date">{ blog.date_published }</small>
                                    <p className="blog__item--content">{ blog.content }</p>
                                </div>
                            ) ) }
                        </li>
                    </ul>
                </div>
            </BlogWrapper>
        </Wrapper>
    )
}

export default BlogList

BlogForm.js

const BlogForm = () => {

    const [inputValues, setInputValues] = useState({
        title : '',
        content : ''
    })

    const handleSubmit = async (event) => {
        event.preventDefault()
        setInputValues({ ...inputValues })

        const { title, content } = inputValues
        const blogPost = { title, content }

        const url = requests.blogCreate
        const response = await axios.post(url, blogPost)
        return response
    }

    const handleChange = (name) => (event) => {
        setInputValues({ ...inputValues, [name] : event.target.value })
    }

    return (
        <div>
            <form onSubmit={ handleSubmit }>
                <input type="text" name="title" placeholder="Title" required value={ inputValues.title } onChange={ handleChange('title') }/>
                <input type="text" name="content" placeholder="Content" required value={ inputValues.content } onChange={ handleChange('content') }/>
                <button type="submit">Submit</button>
            </form>
        </div>
    )
}

export default BlogForm

UPDATED

After the answer from DrewReese, I updated my code and I am getting error when I try to add a new Blog Post. It is showing undefined enter image description here


Solution

  • BlogList has the state you want to be updated from the child component BlogForm. You can pass a callback from parent to child for BlogForm to call with the updated posts.

    BlogList

    const BlogList = (props) => {
        const [blogs, setBlogs] = useState([]);
    
        useEffect(() => {
            async function fetchBlogData() {
                const url = requests.blogList;
                const request = await axios.get(url);
                setBlogs(request.data);
            }
            fetchBlogData();
        }, [props]);
    
        // (1) Define a callback to update state
        const addNewPost = post => setBlogs(posts => [...posts, post]);
    
        return (
            <Wrapper>
                <BlogWrapper className="blog">
    
                    // Blog Form Component Added
                    <BlogForm addNewPost={addNewPost} /> // <-- (2) pass callback
    
                    ...
                </BlogWrapper>
            </Wrapper>
        );
    }
    

    BlogForm

    const BlogForm = ({ addNewPost }) => { // <-- (3) destructure callback
    
        const [inputValues, setInputValues] = useState({
            title : '',
            content : ''
        })
    
        const handleSubmit = async (event) => {
            event.preventDefault()
            setInputValues({ ...inputValues });
    
            const { title, content } = inputValues;
            const blogPost = { title, content };
    
            const url = requests.blogCreate;
            const response = await axios.post(url, blogPost);
            addNewPost(response.data); // <-- (4) call callback with new post data
        }
    
        ...
    
        return (
            ...
        );
    }