skip to Main Content

I want to send the value of an inputbox useing useContext
so i managed to create a context.js as fallow

context.js

import {createContext} from 'react'

const menuContext = createContext('')


export {menuContext}

then use it in menu.js

import React , {useState} from 'react'
import { menuContext } from './helper/context'

 const Menu = () => {
    
  const [text, setText] = useState('')  
     
  return (
    <div>     
      <nav className='navbar navbar-dark bd-dark' dir='rtl'>
        <menuContext.Provider value={text}>
          <form className='form-inline'>                       
            <input 
                className="form-control mr-sm-2" 
                type="search" placeholder="جستجوی نام کالا" 
                aria-label="Search"
                onChange={ (event) =>{
                  setText(event.target.value)
                }}                                                                                                                                                                   
            />                    
          </form>   
        </menuContext.Provider>     
      </nav>                   
    </div>
  )
}

export default Menu;

but in home.js where i want to use the value of inputbox for filtering products i did not get it
what am i missing?

import React , {useState, useEffect, useContext} from 'react'
import { getProducts } from './helper/Coreapicalls';
import Base from './Base';
import Card from './Card';
import "../styles.css"
import { menuContext } from './helper/context';


export default function Home () {

  const [products, setProducts] = useState([]);
  const [filteredProducts, setFilteredProducts] = useState([]) 
  const [error, setError] = useState(false);  
  const [searchIsPresent, setSearchIsPresent] = useState(true);  
  const searchInput = useContext(menuContext)      
  

  const loadAllProducts = () => {
    getProducts()
    .then((data) =>{
      if (data.error){
        setError(data.error);
        console.log(error);
      }
      else{
        setProducts(data);
      }
    })    
  }   

  useEffect(() => {
    loadAllProducts()
  }, []);
  
  function filterItems(arr, query) {
    return arr.filter((el) => el['subbranch3'].toLowerCase().includes(query.toString().toLowerCase()));
  }  
  
  const loadFilteredProducts = () => {
    setFilteredProducts(filterItems(products, searchInput))
    // if (filteredProducts.length !== 0) {
    //   setSearchIsPresent(true)
    // }else{
    //   setSearchIsPresent(false)
    // }    
  }
   
  useEffect ( () => {
    loadFilteredProducts()
  }, [searchInput])  

  const showSearchResult = searchIsPresent =>{
    return(
      searchIsPresent &&
      <div className="row">
         {filteredProducts.map((fProduct, index) =>{
          return(
            <div key={index} className='col-4 mb-4'>
              <Card product={fProduct}/>
            </div>
          )
        })}
      </div>
    )
  }
  
  
  return (
    <Base title='صفحه اصلی' description='به فروشگاه اینترنتی خوش آمدید'>      
      <div>
        {showSearchResult(searchIsPresent)}
      </div>
      <div className="row">
         {products.map((product, index) =>{
          return(
            <div key={index} className='col-4 mb-4'>
              <Card product={product}/>
            </div>
          )
        })}
      </div>
    </Base>
  );
}

when i set menuContext manually in context.js i get the result back but if i input something in textinput nothing brought back as resutl.

any help would be appriciated
Thanks

2

Answers


  1. Your Home component needs to be a child element of the Context Provider in order to use its value. I can’t tell from your question what the component hierarchy looks like, but I’m guessing it’s something like

    > App
      > Menu
        > menuContext.Provider
      > Home : doesn't know about menuContext
    

    I suggest you make the state part of a new component that wraps the provider:

    // MenuContext.js
    const menuContext = createContext({ value: '', setValue() {} })
    
    export useMenuContext = () => useContext(menuContext)
    
    export default function MenuContext (props) {
      const [value, setValue] = useState('')
      return (
        <menuContext.Provider value={{ value, setValue }}>
          {props.children}
        </menuContext.Provider>
      )
    }
    

    then structure your app like

    > App
      > MenuContext
        > Menu : set state with useMenuContext().setValue
        > Home : read useMenuContext().value
    
    Login or Signup to reply.
  2. Your menuContext.Provider wraps the input element, but not the Home component. If you want to share state between Menu and Home, both components must be children of the menuContext.Provider

    Initialise the state in the MenuContext:

    
    import {createContext} from 'react'
    
    const MenuContext = createContext([])
    
    const MenuContextProvider = ({children}) => {
        
        const [text, setText] = useState('') 
    
        return (
            <MenuContext.Provider value={[text, setText]}>
                {children}
            </MenuContext.Provider>
        )
    }
    
    
    export {MenuContext, MenuContextProvider}
    

    Wrap all components that need to access the state with the Provider:

    const App = () => {
    
        return (
               <MenuContextProvider>
                    // ...
                    <Menu />
                    // ...
                    <Home />
               </MenuContextProvider>
        )
    }
    

    Access the state via useContext:

     const Menu = () => {
        
      const [text, setText] = useContext(MenuContext)  
         
      return (
        // ...
    

    If you think it feels a bit clumsy to share the setMenu function via a Context (especially if you want to share more then one setter), consider to useReducer instead of useState – then you only need to share a single dispatcher function for all state manipulation.

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