0

This is the assignment of our university. I tried to add the useEffect to improve my small toy-project to have searchFilter but it says

TypeError: Cannot read property 'filter' of undefined

on useEffect/setSearchFilter part

This was the previous situation of this problem. I feel disaster for this problem holding this for more than 2 days

/[Error image][1]

Can anyone help me with this?

import React, { useState, useEffect } from 'react'
import './App.css';

function App() {
  const [datas, setDatas] = useState([]);
  const [userid, setUserid] = useState('');
  const [searchFilter, setSearchFilter] = useState('');
  const inputChanged = (event) => {
    setUserid(event.target.value)
  }
  useEffect(() => {
    fetch('https://api.github.com/search/repositories?q=react')
    .then(response => response.json())
    .then(data => {
      setDatas(data.items)
    })
  },[])
  useEffect(() => {
    setSearchFilter(
      datas.full_name.filter((result) =>
        result.name.toLowerCase().includes(userid.toLowerCase())
      )
    );
  }, [userid, searchFilter]);
  return (
    <div className="App">
      <h1>Repositories</h1>
        <input 
          id="searchInput"
          type="text" 
          placeholder="search" 
          name="search" 
          value={userid} 
          onChange={inputChanged}
        />
        <button onClick={(e) => setSearchFilter(e.target.value)}>Search</button>
      <table>
        <tbody>
          <tr>
           <th>Name</th>
           <th>URL</th>
          </tr>
          {datas.map((data, index) => 
           <tr key={index}>
             <td>{data.full_name}</td>
             <td><a 
                    target="_blank" 
                    href={data.html_url}
                    >
                      {data.html_url}
                  </a>
            </td></tr>
          )}
        </tbody>
      </table>
    </div>
  );
}
export default App;```



https://stackoverflow.com/questions/67761971/searchfilter-with-using-react-hookuseeffect-usestate/67762090#67762090





  [1]: https://i.stack.imgur.com/RuubM.png
Yajairo87
  • 345
  • 1
  • 8
  • 25

2 Answers2

0

This should work instead of your second useEffect hook if you want to filter on full_name.

useEffect(() => {
    setSearchFilter(
        datas.filter((result) =>
            result.full_name.toLowerCase().includes(userid.toLowerCase())
        )
    );
}, [userid, searchFilter]);
Prayag Choraria
  • 710
  • 5
  • 15
0
  1. You need to filter the array of data on the "full_name" parameter - hence you run the filter() function on the array.
  2. You don't need the search button if you're filtering as the user is typing (since you are using useEffect)

Here's the code:

import React, { useState, useEffect } from 'react'
import './App.css';

function App() {
  const [data, setData] = useState([]);
  const [userID, setUserID] = useState('');
  const [searchResults, setSearchResults] = useState([]);


  //Fetch data when mounted
  useEffect(() => {
    fetch('https://api.github.com/search/repositories?q=react')
    .then(response => response.json())
    .then(data => {
      setData(data.items)
    })
  },[])

  useEffect(() => {
      let result = data.filter((d) =>
      d.full_name.toLowerCase().includes(userID.toLowerCase())
    )
    setSearchResults(result);
  }, [userID, data]);


  const inputChanged = (event) => {
    setUserID(event.target.value)
  }
  
  
  return (
    <div className="App">
      <h1>Repositories</h1>
        <input 
          id="searchInput"
          type="text" 
          placeholder="search" 
          name="search" 
          value={userID} 
          onChange={inputChanged}
        />
        {/* No need for search button if searching using input (useEffect will trigger when typed) 
        <button onClick={search}>Search</button> */}
      <table>
        <tbody>
          <tr>
           <th>Name</th>
           <th>URL</th>
          </tr>
          {searchResults.map((data, index) => 
           <tr key={index}>
             <td>{data.full_name}</td>
             <td><a 
                    target="_blank" 
                    href={data.html_url}
                    >
                      {data.html_url}
                  </a>
            </td></tr>
          )}
        </tbody>
      </table>
    </div>
  );
}
export default App;

Ideally, you would want to handle the loading state and the error state as well.

Nikhil Kothari
  • 235
  • 2
  • 8
  • I have also changed a few variable names as per standard. The original code had `searchFilter` as a string, whereas it should be `searchResults` as it is an array of the data after filtering. Your button component was being clicked and `event.target.value` was being set to the searchFilter. If you want to search after a user clicks, you don't need the useEffect hook. – Nikhil Kothari May 31 '21 at 18:38
  • 1
    "Always keep hooks above the rest of the function code" is ***not*** part of the Rules of Hooks, please check those rules again. – Drew Reese May 31 '21 at 19:48
  • Oh my bad @DrewReese. I always thought the rule "Only Call Hooks at the Top Level" meant that they should be declared first before any other code. I'll change my answer. – Nikhil Kothari May 31 '21 at 19:51