简体   繁体   中英

Update state when imported variable changes using react hooks

I have a searchbar component and a Catalog component. The Catalog component contains different cards. Depending on what is typed in the input field of the searchbar component I want to render different cards.

For this to work I need to be able to import the value of the input field into the Catalog component where it is passed in a search function that handles all the rest of the work.

I am able to import the value into my Catalog component but unfortunaty I can't figure out how I can tell if the imported value has changed so I can search again?

I have found some ways to do this with classes but I would like to use hooks instead. I have experimented a bit with "useEffect" but that didn't work out.

Thank you for your help!

This is my code in the searchbar component:

import React, { useState } from 'react';

let input = "";

function Search() {
  const [value, setValue] = useState(input);

  function onSearch(e) {
    setValue(e.target.value);
    input = value;
  }

  return(
    <form className="searchForm">
      <input className="search" type="text" name="search" autoComplete="off" placeholder="zoeken" value={value} onChange={onSearch}/> </form>
  );
}


export { Search, input };

And this is the code in my Catalog

import React, { useState, useEffect } from 'react';
import {input} from "./search";
// other imports

function Catalog(props){
  //get cards code and fuse code
   
  const [query, setQuery] = useState(input);
  
  function inputHasChanged(){ //function that can tell if the imported input variable changed
    setQuery(input); //update query and rerender cards
  }

  const results = fuse.search(query)
  const searchedCards = query ? results.map(card => card.item) : cards;
  
  //other code

 
  return(
    <div>
       //render the SearchedCards
    </div>
  );
}



export {Catalog};

Solution:

code in search:

import React, { useState } from 'react';


const Search = ({ searching }) => {
  const [value, setValue] = useState("");

  function submit(e){
    setValue(e.target.value);
    searching(value);
  }

  return (
    <form className="searchForm">
      <input
        className="search"
        type="text" name="search"
        autoComplete="off"
        placeholder="zoeken"
        value={value}
        onChange={submit}
      />
    </form>
  );
};

export { Search };

Search is a child of banner:

import React, {useState, useEffect} from 'react';
import {Search} from './search';
import Header from './Header';
import Overzicht from './Overzicht';


const Banner = ({ search }) => {
  const [value, setValue] = useState("");

  useEffect(() => {
    search(value);
  },[search, value]);

  return(
    <div className="banner">
      <Header />
      <Search searching={value => setValue(value)} />
      <Overzicht />
    </div>
  );
};


export default Banner;

Banner is a child of home which also contains Catalog:

import React,  { useState } from "react";
import Banner from './banner';
import {Catalog} from './Catalog';

function Home(){
  const [input, setInput] = useState("");

  return(
    <div>
      <section id="banner">
        <Banner search={input => setInput(input)}/>
      </section>
      <section id="overzicht">
        <Catalog search={input} />
      </section>
    </div>
  );
}

export default Home;

And now I can just call

props.search

In Catalog

Push the common state, the query , up to a common ancestor and pass it down as needed to child and descendant components. This way they can "watch" the changes by having new props passed to them.

Below is a simplified version of a structure that would work:

function Catalog({ query }) {
  const [results, setResults] = useState(null);

  useEffect(() => {
    // If `fuse.search` is asynchronous then you might need to debounce
    // these queries and/or cancel old queries. If a user types "foo",
    // a query is kicked off, and then they finish typing "food", you
    // want to cancel the query for "foo" because the results will no
    // longer be relevant.
    const results = fuse.search(query);
    setResults(results);
  }, [query])

  return (
    <div />
  );
}

function Search({ query, setQuery }) {
  return (
    <input onChange={setQuery} value={query} /> 
  )
}

function App() {
  const [query, setQuery] = useState("");

  return (
    <>
      <Search query={query} setQuery={setQuery} />
      <Catalog query={query} />
    </>
  );
}

You can use useEffect as mentioned below:

useEffect(() => { // Write your logic here

},[input]); // it will run only when the input changes

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM