Search code examples
reactjsstrapi

Hide and show data onSubmit event on imported Component


I would like to hide my data if someone is searching my list items. I have imported my searchbar on Homepage and it seems that the data is not rerendering despite I use a conditional variable with useState.

What I am trying to achieve is the fact that at the beggining the user is seeing the search bar with a list of item. Whenever the user is searching for a string, I want to hide my list of items, as the new data will show. Currently whenever the user is searching does retrieve the search items + initial list of items, which is not ok.

Please find my code:

import React, {useState} from 'react'
import { Link } from 'react-router-dom'
import { useQuery, gql } from '@apollo/client'
import SearchReviews from "./SearchReviews"

const REVIEWS = gql`
  query GetReviews {
    reviews (sort: "createdAt:desc") {
        data{
            ...
                }
              }
            }
        }
    }
  }
`

export default function Homepage() {
    const { loading, error, data } = useQuery(REVIEWS)
    const [ show, setShow] = useState(true)

    if (loading) return <p>Loading...</p>
    if (error) return <p>`Error! ${error}`</p>

    // console.log(data)
    return (
        <div>
            <SearchReviews onSubmit={e => {
                e.preventDefault()
                // console.log(e.target[0].value)
                setShow(false). <==================HERE
            }}/>

            {show && (
                <div>
                        {data.reviews.data.map(review => (
                            <div key={review.id} className="review-card">
                                <div className="rating">{review.attributes.rating}</div>
                                <h2>{review.attributes.title}</h2>
                                <h5>{review.attributes.createdAt.substring(0, 10)}</h5>

                                {review.attributes.categories.data.map(c => (
                                    <small key={c.id}>{c.attributes.name}</small>
                                ))}

                                <p>{review.attributes.body.substring(0, 200)}... </p>
                                <Link to={`/details/${review.id}`}>Read more</Link>
                            </div>
                        ))}
                </div>
                )}
            </div>
    )
}

And with SearchReviews.js


export default function SearchReviews() {
    const [ first, setFirst ] = useState(false)
    const [ query, setQuery] = useState("")

    const { loading, error, data } = useQuery(SEARCH, {skip: !first,variables: {my_query: query}})
    if (loading) return <p>Loading data...</p>
    if (error) return <p>`Error! ${error}`</p>
    // console.log(data)
    return (
        <div>

            <div className="wrap">
                <div className="search">
                    <form onSubmit={e => {
                        e.preventDefault()
                        // console.log(e.target[0].value)
                        setQuery(e.target[0].value)
                        setFirst(true)


                    }}>

                        <input type="search"
                               placeholder="Search Malware"
                               className="searchTerm"
                               id="input_text"
                               autoComplete="off"
                                />
                        <br/>
                        {/*<button type="submit" className="searchButton">Submit</button>*/}
                    </form>
                </div>
            </div>

            {first && (

            <div className="dataResult">
                    {data.reviews.data.map(review => (
                        <div key={review.id} className="review-card">
                        <div className="rating">{review.attributes.rating}</div>
                        <h2>{review.attributes.title}</h2>
                        <h5>{review.attributes.createdAt.substring(0, 10)}</h5>

                        {review.attributes.categories.data.map(c => (
                            <small key={c.id}>{c.attributes.name}</small>
                            ))}

                            <p>{review.attributes.body.substring(0, 200)}... </p>
                            <Link to={`/details/${review.id}`}>Read more</Link>
                            </div>
                            ))}

            </div>
                )}
        </div>
    )
}

Currently the old data is not removed despite the form is submitted, which means that the new state is not re-rendered in the DOM, despite the variable is changed. I think I need to return a boolean value from the child component <SearchReviews /> to parent and change the state.

I tried event with something like this:

    const updateShow = () => {
        setShow(false)
    }

return (
        <div>
            <SearchReviews onChange={updateShow}/>
            <Link to={`/search/`}>Search Library</Link>
            <button> | </button>
            <Link to={`/create`}>Create</Link>
            <button> | </button>
            <Link to={`/new`}>New</Link>
            {show && (
                <div>
                        {data.reviews.data.map(review => (
                            <div key={review.id} className="review-card">
                                <div className="rating">{review.attributes.rating}</div>
                                <h2>{review.attributes.title}</h2>
                                <h5>{review.attributes.createdAt.substring(0, 10)}</h5>

                                {review.attributes.categories.data.map(c => (
                                    <small key={c.id}>{c.attributes.name}</small>
                                ))}

                                <p>{review.attributes.body.substring(0, 200)}... </p>
                                <Link to={`/details/${review.id}`}>Read more</Link>
                            </div>
                        ))}
                </div>
                )}
            </div>
    )

Any help is much appreciated!


Solution

  • You could pass setShow down to the SearchReviews component as props.

    export default function SearchReviews({setShow}) {
        const [ first, setFirst ] = useState(false)
        const [ query, setQuery] = useState("")
    
        // Call the parent function (passed by props) within the child handler
         <form onSubmit={e => {
             e.preventDefault()
             // console.log(e.target[0].value)
             setQuery(e.target[0].value)
             setFirst(true)
             setShow(false)
         }}>
    

    Then in the parent component:

       <SearchReviews setShow={setShow}/>