简体   繁体   中英

filtered data not getting pass from parent component to child component in React

this is how components are look like, i have 3 component that involves in this task, whenever i choose diffrent select dropdown option which is in filter component, change method in parent componet gonna fired and that gonna call another method also in parent component which filterData . its filtering the data but some how after setting state i am not getting filtered data in child component. so i can show filterd data

//parent component


import React, { Component } from 'react';
import ListingsData from '../data/data';
import Listings from '../listings/listings.component';
import Filter from '../filters/filter.component';
import './main_content.styles.scss';


class Main_content extends Component {
    constructor(props) {
        super();
        this.state = {
            listingsData: ListingsData,
            searchOnChange: '',
            filterdProperties: ListingsData,
        }
    }

    change = (e) => {
        this.setState({
            [e.target.name] : e.target.value
        }, () => {
                this.filterData();
            }
        )
    }

    filterData = () => {
        let newData = this.state.listingsData.filter(property => {
            return property.type.toLowerCase().toString() === this.state.houseType.toLowerCase().toString()
        })

        this.setState({ filterdProperties: newData }, () => {
            console.log(this.state)
        });
    }

    render() {
        return (
            <div className='main-content'>
                <div className='listings-container'>
                    <Listings ListingsData={ this.state.filterdProperties } />
                </div>
                <div className='filter-sidebar'>
                    <Filter filterTypeHouse={this.change} />
                </div>
            </div>
        );
    }
}

export default Main_content;



//child component Listing.component.jsx

import React, {Component} from 'react';
import './listings.styles.scss';
import Listing from '../listing/listing.component'

class Listings extends Component {
    constructor(props) {
        super(props);
        this.state = {
            listings: props.ListingsData
        }
    }

    render() {
        if (this.state.listings === undefined || this.state.listings.length === 0) {
            return <h2>sorry no data found</h2>
        }

        return (
            <div className='listings'>
                {this.state.listings.map(({ id, image, address, price, city, rooms, bathrooms, area }) => (
                    <Listing key={id} image={image} address={address} price={price} city={city} rooms={rooms} bathrooms={bathrooms} area={area} />
                ))}
            </div>
        )
    }
}

export default Listings;



//child component filter.component.jsx


import React from 'react';
import './filter.styles.scss';

let Filter = (props) => (
    <div className='filter'>
        <div className='type'>
            <label htmlFor='propertyType'>Type</label>
            <select className='propertyType' name='houseType' onChange={props.filterTypeHouse} >
                <option value='any'>Any</option>
                <option value='family-house'>Family House</option>
                <option value='single-house'>Single house</option>
                <option value='apartment'>Apartment</option>
                <option value='villa'>Villa</option>
                <option value='office-building'>Office Building</option>
                <option value='condo'>Condo</option>               
            </select>
        </div>
        <div className='location'>
        <label htmlFor='PropertyLocation'>Location</label>
            <select className='PropertyLocation'>
                <option>Any</option>
                <option>New york</option>
                <option>California</option>
                <option>Washington</option>
                <option>philedelphia</option>
                <option>Boston</option>               
            </select>
        </div>
        <div className='min-price'>
            <label htmlFor='priceFrom'>Min-Price</label>
            <input type='text' className='priceFrom' placeholder='min-price' />
        </div>
        <div className='max-price'>
            <label htmlFor='priceTo'>Max-Price</label>  
            <input type='text' className='priceTo' placeholder='max-price' />
        </div>
        <div className='dealOption'>
            <label htmlFor='options'>Type Of Deal</label>  
            <div className='options'>
                <div className='each_option'>
                    <label htmlFor='any'>Any</label>  
                    <input type='radio' name='dealType' className='any' value='any' />
               </div>
               <div className='each_option'>
                <label htmlFor='sale'>Sale</label>  
                    <input type='radio' name='dealType' className='sale' value='sale' />
                </div>
                <div className='each_option'>
                    <label htmlFor='rent'>Rent</label>  
                    <input type='radio' name='dealType' className='rent' value='rent' />
                </div>
            </div>
        </div>
    </div>
)

export default Filter;

The component that you use for rendering the filtered lists ( Listings ) is rendering based on state as per below code.

constructor(props) {
        super(props);
        this.state = {
            listings: props.ListingsData
        }
    }

The constructor is called only once when the component is mounted. So, the state will never get modified from the initial state, even if you pass new filtered props. To avoid this behaviour, use the props to display the listings data.

So you can change your Listings component to render from props.

class Listings extends React.Component {

    render() {
        const {ListingData:listings} =  this.props;
        if (listings === undefined || listings.length === 0) {
            return <h2>sorry no data found</h2>
        }

        return (
            <div className='listings'>
                {listings.map(({ id, ...props}) => (
                    <div key={id}>
                      {JSON.stringify(props)}
                    </div>
                ))}
            </div>
        )
    }
}

Try out the below SO snippet. Change the dropdown to apartment, villa, condo to see the filtered data being rendered.

 const ListingsData = [ { type: "apartment", location: "New york" }, { type: "apartment", location: "New york" }, { type: "apartment", location: "New york" }, { type: "villa", location: "New york" }, { type: "condo", location: "New york" }, { type: "condo", location: "Washington" } ]; let Filter = props => { return ( <div className="filter"> <div className="type"> <label htmlFor="propertyType">Type</label> <select className="propertyType" name="houseType" onChange={props.filterTypeHouse} > <option value="any">Any</option> <option value="family-house">Family House</option> <option value="single-house">Single house</option> <option value="apartment">Apartment</option> <option value="villa">Villa</option> <option value="office-building">Office Building</option> <option value="condo">Condo</option> </select> </div> <div className="location"> <label htmlFor="PropertyLocation">Location</label> <select className="PropertyLocation"> <option>Any</option> <option>New york</option> <option>California</option> <option>Washington</option> <option>philedelphia</option> <option>Boston</option> </select> </div> <div className="min-price"> <label htmlFor="priceFrom">Min-Price</label> <input type="text" className="priceFrom" placeholder="min-price" /> </div> <div className="max-price"> <label htmlFor="priceTo">Max-Price</label> <input type="text" className="priceTo" placeholder="max-price" /> </div> <div className="dealOption"> <label htmlFor="options">Type Of Deal</label> <div className="options"> <div className="each_option"> <label htmlFor="any">Any</label> <input type="radio" name="dealType" className="any" value="any" /> </div> <div className="each_option"> <label htmlFor="sale">Sale</label> <input type="radio" name="dealType" className="sale" value="sale" /> </div> <div className="each_option"> <label htmlFor="rent">Rent</label> <input type="radio" name="dealType" className="rent" value="rent" /> </div> </div> </div> </div> ); } class Listings extends React.Component { render() { const {ListingData:listings} = this.props; if (listings === undefined || listings.length === 0) { return <h2>sorry no data found</h2> } return ( <div className='listings'> {listings.map(({ id, ...props}) => ( <div key={id}> {JSON.stringify(props)} </div> ))} </div> ) } } class Main_content extends React.Component { constructor(props) { super(); this.state = { listingsData: ListingsData, searchOnChange: '', filterdProperties: ListingsData, } } change = (e) => { console.log("Calling change handler"); this.setState({ [e.target.name]: e.target.value }, () => { this.filterData(); } ) } filterData = () => { console.log("Calling filter data"); let newData = this.state.listingsData.filter(property => { return property.type.toLowerCase().toString() === this.state.houseType.toLowerCase().toString() }) this.setState({ filterdProperties: newData }, () => { console.log("State", this.state); }); } render() { return ( <div className="main-content"> <div className="listings-container"> <Listings ListingData={this.state.filterdProperties} /> </div> <div className="filter-sidebar"> <Filter filterTypeHouse={this.change} /> </div> </div> ); } } ReactDOM.render(<Main_content />,document.getElementById("root"));
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script> <div id="root"></div>

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