Home > database >  React local JSON data filtering using usEffect Hooks
React local JSON data filtering using usEffect Hooks

Time:03-22

I've been working on a user display for an engineering page and was trying to display and filter the data based on the following criteria of field and expertise. Fields can be filtered through the selection of a dropdown menu while expertise can be filtered via input. I initially wanted to load just the default json file onto the page once the user reaches the page, and then filter this data based on whatever filters the user has selected. I figured the best approach to do this would be via a useEffect hook, but for whatever reason when I follow this route, the initial data being loaded is not all the data from the local json file and returns a single card with empty values. In addition, I also been running into an issue where the user decides to filter both by field and expertise which results in an error and crashes the page. If anyone could provide assistance or guidance on how to implement multiple filtering via useEffect hooks would be greatly appreciated!

import React, { useState, useEffect } from 'react'; 
import { Row, Col, Container } from "react-bootstrap";


import "./engineerDashboard.css"; // Import styling
import engineerData from "./EngineerDashboard.json"


function EngineerDashboard() {


    const [searchSelect, setSearchSelect] = useState('');
    const [searchInput, setSearchInput] = useState('');
    const [engineers, setEngineers] = useState([engineerData]);
    const [sortedEngineers, setSortedEngineers] = useState([]);

    console.log(sortedEngineers)
    

    
    useEffect(() => {
        let result = [...engineers];
    
        if(searchInput) {
          result = result[0].engineers.filter(item => item.tools === searchInput);      
        }
    
        if(searchSelect) {
          result = result[0].engineers.filter(item => item.field === searchSelect);      
        }
        setSortedEngineers(result);
    
    }, [searchSelect, engineers, searchInput]);
    

    return (
        <div>
            <Container fluid className="content-block">
            
            <Container fluid className="header-block">
                <Row >
                    <h2>Find Engineers</h2>

                    <Col sm={3}>
                        <div className="pageHeaderComponent">
                            <p className="componentLabel">Field:</p>
                            <select 
                                className="search-select"
                                onChange={e => setSearchSelect(e.target.value)}    
                            >
                                <option key="Software" value="Software">Software</option>
                                <option key="Design" value="Design">Design</option>
                                <option key="Hardware" value="Hardware">Hardware</option>
                                <option key="Cybersecurity" value="Cybersecurity">CyberSecurity</option>
                            </select>
                        </div>
                    </Col>

                    <Col sm={3}>
                        <div className="pageHeaderComponent">
                            <p className="componentLabel">Expertise:</p>
                            <input className="search-input" onChange={e => setSearchInput(e.target.value)}></input>
                        </div>
                    </Col>
                </Row>
            </Container>

              { sortedEngineers.length > 0 &&
                <Row style={{ paddingTop: "20px", marginTop: "20px" }}>
                    { sortedEngineers.map((item, i) => (
                    <Col md={3} sm={6} className="contact-card" key={i}>
                        <div className="inner">
                            <h2>{item.name}</h2>
                            <p className="mt-3 mb-4">Field: {item.field}</p>
                            <p className="mt-3 mb-4">Tools Expertise:</p>
                            <p className="mt-3 mb-4">{item.tools}</p>
                            <p className="mt-3 mb-4">Availability: {item.availability</p>        
                        </div>
                    </Col>
                    ))}
                </Row>
                }
                
            </Container>
        </div>
    )
}

export default EngineerDashboard;

CodePudding user response:

It's showing only one card with no data because you are setting your JSON object inside an array which in terms creates an array with one element. Instead of setting the engineerData inside array, set the engineerData directly, like this:

const [engineers, setEngineers] = useState(engineerData);

I don't have any idea about your JSON file format but you can go from here I guess.

CodePudding user response:

We can make a number of simplifications here that will, as a side-effect (pardon the pun) fix this problem.

You're placing too much into your React state. If your initial engineer data has come from a local JSON file, why then copy it into state in a useEffect? Just use it!

By the way, there was a clue here - setEngineers was never being called.

If we eliminate the engineers from your useEffect, we get:

  useEffect(() => {
    let result = [...engineerData];

    if (searchInput) {
      result = engineerData.filter((item) => item.tools === searchInput);
    }

    if (searchSelect) {
      result = engineerData.filter((item) => item.field === searchSelect);
    }
    setSortedEngineers(result);
  }, [searchSelect, searchInput]);

This is already better, but we can go further. If you read down your function like React does, nothing is going to be done on the first pass - it's all happening after the first render. sortedEngineers is really just showing the result of applying the user's selections - so why not just make it explicit, remove the useEffect entirely, and perform the filter each time React calls us?

function EngineerDashboard() {
  const [searchSelect, setSearchSelect] = useState("");
  const [searchInput, setSearchInput] = useState("");
  let sortedEngineers = [...engineerData];

  if (searchInput) {
    sortedEngineers = engineerData.filter((item) => item.tools === searchInput);
  }

  if (searchSelect) {
    sortedEngineers = sortedEngineers.filter(
      (item) => item.field === searchSelect
    );
  }

  return (
  ...
  )
}

  • Related