Javascript 动态更新父状态

Javascript 动态更新父状态,javascript,reactjs,Javascript,Reactjs,我试图根据子组件的输入值更新父组件的状态,并再次渲染组件 我有应用程序、地图和ListPlaces组件。 地图组件显示地图和标记,并将应用程序组件中的标记作为道具 ListPlaces组件有自己的状态(searchQuery)和方法(updateQuery)。基本上,它使用regexp并根据输入过滤结果,并在列表元素中显示过滤后的值。这很好,但是,我需要的远不止这些。我想在这里做什么?根据输入值的更改,我想更新我的标记(应用程序组件中的状态)并再次重新渲染我的地图组件,以仅显示地图上的相关标记。

我试图根据子组件的输入值更新父组件的状态,并再次渲染组件

我有应用程序、地图和ListPlaces组件。 地图组件显示地图和标记,并将应用程序组件中的标记作为道具

ListPlaces组件有自己的状态(searchQuery)和方法(updateQuery)。基本上,它使用regexp并根据输入过滤结果,并在列表元素中显示过滤后的值。这很好,但是,我需要的远不止这些。我想在这里做什么?根据输入值的更改,我想更新我的标记(应用程序组件中的状态)并再次重新渲染我的地图组件,以仅显示地图上的相关标记。这个想法很基本,但我无法实现

当我尝试更改实际上是数组的标记时,它将是0。我将分享我的所有代码,但我需要说,我认为问题可能与输入元素(ListPlaces)中的onChange方法有关。

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);
            });
    }

    openInfo = (e, id) => {
        this.setState({
            markerID: id
        });
    };

    closeInfo = () => {
        this.setState({
            markerID: -1
        });
    };

    changeMarkers = newValue => {
        const newmarkers = this.state.places.filter(
            place => place.name === newValue
        );
        this.setState({
            markers: newmarkers
        });
    };

    toggleListPlaces = () => {
        const nav = document.getElementById("nav-toggle");
        const body = document.getElementsByTagName("body")[0];

        nav.classList.toggle("active");

        if (body.classList.contains("show-nav")) {
            body.classList.remove("show-nav");
        } else {
            // If sidebar is hidden:
            body.classList.add("show-nav");
        }
    };

    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="map_url"
                    loadingElement={<div style={{ height: "100%" }} />}
                    containerElement={<div style={{ height: "100%" }} />}
                    mapElement={<div style={{ height: "100%" }} />}
                />
                <ListPlaces
                    toggleListHandler={this.toggleListPlaces}
                    locations={this.state.places}
                    openInfoHandler={this.openInfo}
                    changeMarkersHandler={this.changeMarkers}
                />
            </div>
        );
    }
}

export default App;
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>Information provided by Foursquare</p>
                </aside>
                <a
                    onClick={toggleListHandler}
                    id="nav-toggle"
                    className="position"
                >
                    <span />
                </a>

            </div>
        );
    }
}

export default ListPlaces;
类应用程序扩展组件{
建造师(道具){
超级(道具);
此.state={
地点:[],
标记:[],
马克里德:-1,
新标记:[]
};
this.changeMarkers=this.changeMarkers.bind(this);
}
componentDidMount(){
取回(
“api_url”
)
.then(response=>response.json())
。然后(数据=>{
这是我的国家({
地点:data.response.Victories、,
标记:data.response.viouses
});
})
.catch(错误=>{
log(“出错了”,错误);
});
}
openInfo=(e,id)=>{
这是我的国家({
markerID:id
});
};
closeInfo=()=>{
这是我的国家({
马克里德:-1
});
};
changeMarkers=newValue=>{
const newmarkers=this.state.places.filter(
place=>place.name==newValue
);
这是我的国家({
标记:新标记
});
};
toggleListPlaces=()=>{
const nav=document.getElementById(“导航切换”);
const body=document.getElementsByTagName(“body”)[0];
导航类列表切换(“活动”);
if(body.classList.contains(“show nav”)){
body.classList.remove(“显示导航”);
}否则{
//如果侧栏被隐藏:
body.classList.add(“显示导航”);
}
};
render(){
返回(
);
}
}
导出默认应用程序;
列表位置

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);
            });
    }

    openInfo = (e, id) => {
        this.setState({
            markerID: id
        });
    };

    closeInfo = () => {
        this.setState({
            markerID: -1
        });
    };

    changeMarkers = newValue => {
        const newmarkers = this.state.places.filter(
            place => place.name === newValue
        );
        this.setState({
            markers: newmarkers
        });
    };

    toggleListPlaces = () => {
        const nav = document.getElementById("nav-toggle");
        const body = document.getElementsByTagName("body")[0];

        nav.classList.toggle("active");

        if (body.classList.contains("show-nav")) {
            body.classList.remove("show-nav");
        } else {
            // If sidebar is hidden:
            body.classList.add("show-nav");
        }
    };

    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="map_url"
                    loadingElement={<div style={{ height: "100%" }} />}
                    containerElement={<div style={{ height: "100%" }} />}
                    mapElement={<div style={{ height: "100%" }} />}
                />
                <ListPlaces
                    toggleListHandler={this.toggleListPlaces}
                    locations={this.state.places}
                    openInfoHandler={this.openInfo}
                    changeMarkersHandler={this.changeMarkers}
                />
            </div>
        );
    }
}

export default App;
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>Information provided by Foursquare</p>
                </aside>
                <a
                    onClick={toggleListHandler}
                    id="nav-toggle"
                    className="position"
                >
                    <span />
                </a>

            </div>
        );
    }
}

export default ListPlaces;
类ListPlaces扩展组件{
状态={
搜索查询:“
};
updateQuery=query=>{
this.setState({searchQuery:query});
};
render(){
const{toggleListHandler,locations,openInfoHandler,changeMarkerHandler}=this.props;
让展示地点;
if(this.state.searchQuery){
const match=new RegExp(escapeRegExp(this.state.searchQuery),“i”);
showLocations=locations.filter(location=>match.test(location.name));
}否则{
showLocations=位置;
}
返回(
餐厅
{this.updateQuery(e.target.value);changeMarkerHandler(e.target.value)}
/>
    {showLocations.map(位置=>{ 返回(
  • openInfoHandler(e,location.id) } > {location.name}
  • ); })}
Foursquare提供的信息

); } } 导出默认列表位置;
地图

const Map = withScriptjs(withGoogleMap((props) =>

    <GoogleMap
        defaultZoom={14}
        defaultCenter={{ lat: 48.2854790, lng: -143.1407394 }}
        >
        {props.markers.map(restaurant => {
            let marker = (
                <Marker
                    id={restaurant.id}
                    key={restaurant.id}
                    name={restaurant.name}
                    position={{lat: restaurant.location.lat, lng: restaurant.location.lng}}
                    address={restaurant.location.address}
                    defaultAnimation={window.google.maps.Animation.DROP} // Should be 1 or 2 according to Stackoverflow
                    onClick={e => {props.openInfoHandler(e, restaurant.id)}}
                    animation = {props.markerID === restaurant.id && window.google.maps.Animation.BOUNCE}
                    >
                    {props.markerID === restaurant.id && (
                    <InfoWindow onCloseClick={e => {props.closeInfoHandler()}}>
                      <div className="info-window">
                        <p className="restaurant-name">{restaurant.name}</p>
                        <p className="restaurant-address">{restaurant.location.address}</p>
                      </div>
                      </InfoWindow>
                        )}

                    </Marker>
                );
            return marker;
        })}

        </GoogleMap>
    ))

export default Map;
const Map=withScriptjs(withGoogleMap((道具)=>
{props.markers.map(餐厅=>{
让标记=(
{props.openInfoHandler(e,restaurant.id)}
动画={props.markerID==restaurant.id&&window.google.maps.animation.BOUNCE}
>
{props.markerID===restaurant.id&&(
{props.closeInfoHandler()}}>

{restaurant.name}

{restaurant.location.address}

)} ); 返回标记; })} )) 导出默认地图;
您走在正确的轨道上-您需要将筛选值/筛选操作提升到公共父级

App.js

class App extends React.Component {
  onChangeFilter = (newFilter) => {
    this.setState({ filter: newFilter })
  }

  render () {
    const { filter, places } = this.state
    const mPlaces = places.filter(/* filter places here */)

    return (
      <div className="App">
        <ListPlaces 
          places={ mPlaces }
          onChangeFilter={ this.onChangeFilter }
          ...
        />

        <Map 
          locations={ mPlaces }
          ...
        />
      </div>
    )
  }
}
class ListPlaces extends React.Component {
  updateQuery = (query) => {
    this.props.onChangeFilter(query)
  }

  ...
}

这是React中的一种常见模式,非常常见。

我不明白。你能更具体地说明代码细节吗?请不要诋毁你的问题。这个问题和答案是为所有访问该网站的人准备的。根本没有答案!