How to filter JSON data from API and setState in React

16,937

When you set the state with the filtered result you are removing entries from the source. You should instead store the filtered result in a different key.

For instance something like this.

const jeepAutos = autos.filter( (auto) => auto.title.includes("Jeep"))
this.setState({
  filteredAutos: jeepAutos
})

Then when rendering you would use it like so

<AutoList autos={ this.state.filteredAutos } />

Remember that initially filteredAutos would be empty, so to view all you would need to check for filtered items before passing

<AutoList autos={ filteredAutos.length > 0 ? filteredAutos : autos } />

Simple example to play with

Share:
16,937
J. Gunderson
Author by

J. Gunderson

Updated on December 13, 2022

Comments

  • J. Gunderson
    J. Gunderson over 1 year

    Upon clicking a filter button, the first filter returns the correct data, but the array in state is mutated (or destroyed?) when a second filter method is called. I'm using setState for each function and cannot figure out why the array's initial state is not restored.

    This app is working when I import a local copy of the JSON data. The blocks of commented code do indeed show that the filter functions work with the local data, but not with the same JSON data returned by the fetch method from my server.

    import React from "react";
    import { Button, Row, Col } from "react-bootstrap";
    import AutoList from './AutoList';
    // import autoData from '../autoData.json';
    
    const API = "https://MY_SERVER/autoData.json";
    
    class GetAutos extends React.Component {
      constructor(props) {
        super(props);
    
        this.state = {
          autos: [],
        };
      }
    
      fetchAutoData() {
          fetch(API)
            .then(autoData => autoData.json())
            .then(autoData =>
                this.setState({
                    autos: autoData, 
                    isLoading: false,
                })
            )
            .catch(error => this.setState({ error, isLoading: false }));
    
      }
    
      componentDidMount() {
          this.fetchAutoData();
          // this.setState(() => ({ autos: autoData }));
      }
    
    
      render() {
    
        const { autos } = this.state;
    
        let onResetArray = () => {
            this.setState({ autoData: this.state.autos })
            //console.log(autos)
          }
    
        let filterFord = () => {
            const fordAutos = autos.filter( (auto) => auto.title.includes("Ford"));
            // const fordAutos = autoData.filter( (auto) => auto.title.includes("Ford"));
    
            this.setState({ autos: fordAutos });
        }
    
    
        let filterChevy = () => {
            const chevyAutos = autos.filter( (auto) => auto.title.includes("Chevrolet"));
            // const chevyAutos = autoData.filter( (auto) => auto.title.includes("Chevrolet"));
    
            this.setState({ autos: chevyAutos });
        }
    
        let filterJeep = () => {
            const jeepAutos = autos.filter( (auto) => auto.title.includes("Jeep"));
            // const jeepAutos = autoData.filter( (auto) => auto.title.includes("Jeep"));
    
            this.setState({ autos: jeepAutos });
        }
        return (
            <div className="container">
                <Row className="mb-4">
                    <Col>
                        <Button event-key="reset-autos" onClick={onResetArray}>All Cars</Button>
                    </Col>
                    <Col>
                        <Button event-key="ford-autos" onClick={filterFord}>Filter Ford</Button>
                    </Col>
                    <Col>
                        <Button event-key="chevy-autos" onClick={filterChevy}>Filter Chevy</Button>
                    </Col>
                    <Col>
                        <Button event-key="jeep-autos" onClick={filterJeep}>Filter Jeep</Button>
                    </Col>
                </Row>
    
    
            <AutoList autos={ this.state.autos } />
            </div>
    
        );
      }
    }
    export default GetAutos;
    

    I expect a subsequent button click to filter the data set in state. Instead, the click filters the array created by the .filter() method. My code works with a local import of my JSON data, but not with the fetched JSON.

    • John Ruddell
      John Ruddell over 4 years
      you need to not apply the filter on the state array itself, instead make a copy of the state array. const autos = [...this.state.autos]. Next you need to keep them in a different array so you dont lose the data. I would put those filter methods on the class instead of defining them in the render also