我试图根据孩子的组件输入值更新父组件的状态,然后再次渲染组件。
我有App,Map和ListPlaces组件。 地图组件显示地图和标记,并以App组件中的标记为道具。
ListPlaces组件具有自己的状态(searchQuery)和一个方法(updateQuery)。基本上,它使用regexp并根据输入过滤结果,并在 list元素中显示过滤后的值。很好,但是,我需要的还不止这些。我想在这里做什么?根据输入值的更改,我想更新我的标记(App组件中的状态),然后再次重新渲染地图组件以在地图上仅显示相关的标记。想法是基本的,但我无法实现。
当我尝试更改实际上是数组的标记时,它将为0。我将共享我的所有代码,但我需要说 我认为问题可能与输入中的onChange方法有关元素(ListPlaces)
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;
ListPlaces
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;
地图
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;
答案 0 :(得分:1)
您处在正确的轨道上-您需要将过滤器值/过滤器操作提升到公共父级
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>
)
}
}
ListPlaces.js
class ListPlaces extends React.Component {
updateQuery = (query) => {
this.props.onChangeFilter(query)
}
...
}
这是React中的常见模式-如此普遍it has its own page in the React docs。