1

I have 3 components: App, Map and ListPlaces. In ListPlaces component, when a user types something in the input element, I want to change the state(markers's state) in App.js to show only related markers on the map.

Edit: When I edit my typo, the error was disappeared. However, I think the logic is still wrong. Because when I write something in the input element, markers array would be 0 immediately. And of course, all markers are disappeared.

More Explanation:

After componentDidMount, my markers array holds 7 items. And Map component takes this markers array and render markers on the map. However, I need to control my markers from ListPlaces component according to value of input element. So I put this: onChange={e => {this.updateQuery(e.target.value); changeMarkersHandler(e.target.value)}} in onChange attribute of input element. (Omit the this.updateQuery, for now, you can focus on only changeMarkersHandler).

This changeMarkersHandler runs changeMarkers function in App.js, but I don't know why my marker arrays would be 0 immediately while changeMarkers function is working.

Note: I am using react-google-maps and I've omitted some code blocks which aren't related to question.

App.js

class App extends Component {
    constructor(props) {
        super(props);
        this.state = {
            places: [],
            markers: [],
            markerID: -1,
            newMarkers: []
        };
        this.changeMarkers = this.changeMarkers.bind(this);
    }

    componentDidMount() {
        fetch("api_url")
            .then(response => response.json())
            .then(data => {
                this.setState({
                    places: data.response.venues,
                    markers: data.response.venues
                });
            })
            .catch(error => {
                console.log("Someting went wrong ", error);
            });
    }


    changeMarkers(value) {
        const newMarkers = this.state.markers.filter(
            place => place.name === value
        );
        this.setState({
            newMarkers : newMarkers,
            markers: newMarkers
        })
    }

    render() {
        return (
            <div className="App">
                <Map role="application"
                places={this.state.places}
                markers={this.state.markers}
                openInfoHandler={this.openInfo}
                closeInfoHandler={this.closeInfo}
                markerID={this.state.markerID}
                googleMapURL="url_here" />
                <ListPlaces changeMarkersHandler={this.changeMarkers} />
            </div>
        );
    }
}

ListPlaces.js

import React, { Component } from "react";
import escapeRegExp from "escape-string-regexp";

class ListPlaces extends Component {
    state = {
        searchQuery: ""
    };

    updateQuery = query => {
        this.setState({ searchQuery: query});
    };

    render() {
        const { toggleListHandler, locations, openInfoHandler, changeMarkersHandler} = this.props;
        let showLocations;
        if (this.state.searchQuery) {
            const match = new RegExp(escapeRegExp(this.state.searchQuery), "i");
            showLocations = locations.filter(location =>match.test(location.name));
        } else {
            showLocations = locations;
        }

        return (
            <div>
                <aside>
                    <h2>Restaurants</h2>
                    <nav>
                        <div className="search-area">
                            <input
                                className="search-input"
                                type="text"
                                placeholder="Search Restaurant"
                                value={this.state.searchQuery}
                                onChange={e => {this.updateQuery(e.target.value); changeMarkersHandler(e.target.value)}}
                            />
                        </div>
                        <ul>
                            {showLocations.map(location => {
                                return (
                                    <li
                                        key={location.id}
                                        onClick={e =>
                                            openInfoHandler(e, location.id)
                                        }
                                    >
                                        {location.name}
                                    </li>
                                );
                            })}
                        </ul>
                    </nav>
                    <p>some text</p>
                </aside>
                <a
                    onClick={toggleListHandler}
                    id="nav-toggle"
                    className="position"
                >
                    <span />
                </a>

            </div>
        );
    }
}

export default ListPlaces;
blocker
  • 85
  • 9
  • Possible duplicate of [Can't call setState on a component that is not yet mounted](https://stackoverflow.com/questions/50162522/cant-call-setstate-on-a-component-that-is-not-yet-mounted) – Raman Mishra Aug 08 '18 at 09:17
  • @RamanMishra I definetely checked the similar questions and applied different solutions. Anyway, the error was related to typo. After I edited the typo, now I have a logic error! – blocker Aug 08 '18 at 09:28
  • In `ListPlaces.js`, what is the `this.updateQuery()`? – Yonggoo Noh Aug 08 '18 at 09:41
  • @YonggooNoh this.updateQuery takes value and shows the related locations in just the **list** element (It is not all about the showing markers on map). Basically ListPlaces has own state and updateQuery method. I am using "escape-string-regexp" for that. – blocker Aug 08 '18 at 09:51
  • In `ListPlaces.js` you have one function call and one state call, where no initial state is set, which are not in the provided code example. maybe this is the error? 'this.updateQuery` and `this.state.searchQuery` – Mario Aug 08 '18 at 09:52
  • OK I am now adding all ListPlaces.js, please take a look at my question again. – blocker Aug 08 '18 at 09:53

1 Answers1

2

You have a typo in you constructor.

 this.changeMarkers(this.changeMarkers.bind(this));

should be

 this.changeMarkers = this.changeMarkers.bind(this);
ztadic91
  • 2,526
  • 1
  • 11
  • 17
  • I edited the typo, but I have still a logic error. I edited my question to explain my logic error. @ztadic91 – blocker Aug 08 '18 at 09:27