Home > other >  how to set a state in function components depending on changehandler
how to set a state in function components depending on changehandler

Time:11-12

I have this Body Component set:

import 'bootstrap/dist/css/bootstrap.css';
import {Container} from "react-bootstrap";
import Navigation from './Navigation'
import axios from 'axios'
import {useState,useEffect} from "react";


function Body() {
    const [searchItems, setSearchItems] = useState([{}])

    useEffect(() => {
        console.log(searchItems)
    }, [])

    return (
        <Container>
            <Navigation setSearchItems={setSearchItems}/>
        </Container>
    );
}

export default Body;

And here is my Navigation Component with an Inputfield as anther component named SearchInput. As you can see I pass the setSearchItems from the start to each child, because I want to use the searchItems-Array to display some data later:

import Navbar from 'react-bootstrap/Navbar';
import Form from 'react-bootstrap/Form';
import {InputGroup} from "react-bootstrap";
import axios from 'axios';
import {useState, useEffect} from "react";

const api_key = process.env.API_KEY;

const SearchInput = (setSearchItems) => {
    async function changeHandler(e, setSearchItems) {
        if (e.target.value.length > 2) {
            const url = 'https://api.thedogapi.com/v1/breeds/search?q='   e.target.value
            const config = {
                method: 'GET',
                mode: 'cors',
                headers: {
                    'x-api-key': api_key
                }
            }
            const data = await axios.get(url, config)
            setSearchItems(data['data'])
        }
    }

    return (
        <InputGroup style={{
            marginLeft: '50px',
            marginRight: '50px',
            paddingTop: '10px',
            paddingBottom: '10px',
            width: '50%'
        }}>
            <Form.Control
                placeholder="Enter Dogs Breed"
                aria-label="Breed"
                onChange={(e) => changeHandler(e, setSearchItems)}
            />
        </InputGroup>
    )
}

const Navigation = (setSearchInput) => {
    return (
        <Navbar fixed="top" bg='light'>
            <SearchInput setSearchInput={setSearchInput}/>
        </Navbar>
    )
}

export default Navigation;

everytime I try to call setSearchItems, I get Uncaught (in promise) TypeError: setSearchItems is not a function

I also tried this version of changeHandler before:

async function changeHandler(e) {
    if (e.target.value.length > 2) {
        const url = 'https://api.thedogapi.com/v1/breeds/search?q='   e.target.value
        const config = {
            method: 'GET',
            mode: 'cors',
            headers: {
                'x-api-key': api_key
            }
        }
        await axios.get(url, config)
            .then((response) => setSearchItems([response.data]))
    }
}

but it's an error al the time

CodePudding user response:

Try destructuing it in parameters of component like this: const Component =({setSearchItems}) => {}. It could work because the object that is given to component is actually params that holds all arguments

CodePudding user response:

You could use the concept of prop drilling in React by passing the props from parent to child component and getting values from child components. In your case, Body is the body component so you can basically drill the states through components.

So, your Body component looks like this

import "bootstrap/dist/css/bootstrap.css";
import { Container } from "react-bootstrap";
import Navigation from "./navigation";
import { useState } from "react";

function Body() {
  const [searchItems, setSearchItems] = useState([]);
  const [searchInput, setSearchInput] = useState("");

  return (
    <Container>
      <Navigation
        setSearchItems={setSearchItems}
        setSearchInput={setSearchInput}
      />
      <ul>
        {searchItems.map((item, index) => (
          <li key={index}>{item.name}</li>
        ))}
      </ul>
    </Container>
  );
}

export default Body;

and the Navigation component is

import Navbar from "react-bootstrap/Navbar";
import SearchInput from "./search";

const Navigation = ({ setSearchItems, setSearchInput }) => {
  return (
    <Navbar fixed="top" bg="light">
      <SearchInput
        setSearchInput={setSearchInput}
        setSearchItems={setSearchItems}
      />
    </Navbar>
  );
};

export default Navigation;

and finally Search component is getting the setSearchItems as prop and adding the array to it.

import axios from "axios";
import { InputGroup } from "react-bootstrap";
import Form from "react-bootstrap/Form";
const api_key = process.env.API_KEY;

const SearchInput = ({ setSearchItems }) => {
  async function changeHandler(e) {
    if (e.target.value.length > 2) {
      const url =
        "https://api.thedogapi.com/v1/breeds/search?q="   e.target.value;
      const config = {
        method: "GET",
        mode: "cors",
        headers: {
          "x-api-key": api_key
        }
      };
      const data = await axios.get(url, config);
      console.log(data);

      setSearchItems(data["data"]);
    }
  }

  return (
    <InputGroup
      style={{
        marginLeft: "50px",
        marginRight: "50px",
        paddingTop: "10px",
        paddingBottom: "10px",
        width: "50%"
      }}
    >
      <Form.Control
        placeholder="Enter Dogs Breed"
        aria-label="Breed"
        onChange={(e) => changeHandler(e)}
      />
    </InputGroup>
  );
};

export default SearchInput;

I have added the working demo version here.

  • Related