skip to Main Content

I was looking over React: Reverse data Flow, to update foodObj, input and buttonClicked declared in Main.js (Parent Component) using the child component <SearchAndSuggestion>. Here are the two files.

my-app/app/page.js (Parent File)-

    'use client'
import React, {useState} from 'react'
import FoodList from "./today_page/list/page";
import NutritionTable from "./today_page/nutrition_table/page";
import SearchAndSuggestion from "./today_page/search_and_suggestions/page";

export default function Home() {

const [foodObj, setFoodObj] = useState({});
const [input, setInput] = useState("");
const [buttonClicked, setButtonClicked] = useState(false);

const buttonF = (value) => {
    setButtonClicked(value)
}

const inputF = (value) => {
    setInput(value)
}

const foodObjF = (value) => {
    setFoodObj(value)
}


return (
    <main className="flex flex-row overflow:hidden items-center justify-between p-24">
        ...
    <div className='flex flex-col m-4 border-blue-600'>
        ...
        {/* right side upper half*/}
        <SearchAndSuggestion foodObjF={foodObjF} inputF = {inputF} buttonF ={buttonF}/>
        ...
    </div>

    <p>{foodObj + ", " + input + ", " + buttonClicked}</p>
</main>
)

}

my-app/app/today_page/seaerch_and_suggestion/page.js (Child Component) –

'use client'

import { useEffect } from "react"

const SearchAndSuggestion = ({foodObjF, inputF, buttonF}) => {

    let query = " "

    const updateObj = (obj, query) => {
        if(obj && typeof obj === 'object'){
            if(!obj.hasOwnProperty(query)){
                obj[query] = 1
            }else{
                obj[query]++
            }
        }
        return obj
    }

    const handleClick = () => {
        if(query != " "){
            inputF(query)
            foodObjF(prevObj => updateObj(prevObj, query))
            buttonF(true)
            query = " "
            document.getElementById('myInput').value = ''
        }else{
            console.log("Failed")
        }
    }

    return (
        // Search bar, button with suggestion box
        <div className='flex flex-col flex-wrap box-border bg-gray-500 rounded-2xl border-gray-950 border-r-blue-600'>
            <form className='flex flex-row'>
                <input
                    id = "myInput"
                    className='m-2 w-120 h-8 rounded-2xl'
                    onChange = {(e) => {
                        query = e.target.value
                    }}
                    />
                <button 
                    className='w-20 h-8 bg-white m-2 rounded-2xl'
                    type='button'
                    onClick = {() => handleClick}
                    >
                    Find
                </button>
            </form>

            <div className='box-border h-48 w-144 m-2 bg-gray-300 border-1 rounded-2xl bg-grey-200'>
            </div>
        </div>
    )
}

export default SearchAndSuggestion

The problem is that whenever I enter something in the input made inside <SearchAndSuggestion>, it doesn’t change <p>{foodObj + ", " + input + ", " + buttonClicked}</p> written in Parent component file. I am not sure where the problem exist. Could someone point it out?

Thanks!

2

Answers


  1. Firstly, in the button’s click handler, you’re not calling the handleClick function, you’re just returning it.

    Should look like this:

    ...
    <button 
        className='w-20 h-8 bg-white m-2 rounded-2xl'
        type='button'
        onClick={()=>handleClick()}
    >
        Find
    </button>
    ...
    

    or better still pass is directly to the onClick handler:

    ...
    <button 
        className='w-20 h-8 bg-white m-2 rounded-2xl'
        type='button'
        onClick={handleClick}
    >
        Find
    </button>
    ...
    

    Secondly, you can’t set a variable in react the way you did in the input’s onChange handler.

    You have to make query a state and make the input controlled.
    Like so:

    ...
    const [query, setQuery] = useState("");
    ...
    
    ...
    <input
        id = "myInput"
        className='m-2 w-120 h-8 rounded-2xl'
        value={query}
        onChange = {(e) => {
            setQuery(e.target.value);
        }}
    />
    ...
    
    Login or Signup to reply.
  2. You’re first using a local variable and not state when you’re changing query, so you will not get a re-render since react will only re-render a component when state(s) change. I think it may be best to understand controlled inputs in react (simply, you have to use state var as the value of the input and on the specific event, update that state).

    In your case, you could send both the input (state) and the setState fn for that input.

    <input
     id = "myInput"
     className='m-2 w-120 h-8 rounded-2xl'
     value={input}
     onChange = {(e) => inputF(e.target.value)}
    />
    
    

    seems like another commenter also mentioned it as well.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search