我正在React工程中使用Google Maps API进行地图的简单实现。当用户单击基于状态对象中infoWindowStatus的状态的标记时,向他们显示一个信息窗口。如果infoWindowStatus为true,则显示信息窗口。
如果我直接更改状态并使用forceUpdate,则信息窗口会正确显示。当我使用setState时,不会显示信息窗口。 (但是,当我console.log this.state.locations [myKey] .infoWindowStatus时,我可以看到infoWindowStatus确实从false变为true。)
我遇到的问题是:
使用this.setState和来自immutability-helper的更新不会重新渲染React组件。
import update from 'immutability-helper';
state = {
locations : [
{
position: {lat: 41.3029876, lng: -72.9191306},
title: "Pepe's Pizza",
mappy: '',
infoWindowStatus: false,
key : 0,
infoWindow :
{
content : "Loading...",
contentUrl : ""
}
}
]
}
// THIS DODGEY CODE WORKS
this.state.locations[myKey].infoWindowStatus = true;
this.forceUpdate()
//THIS CODE DOES NOT WORK
this.setState(
{ locations: update(this.state.locations, { [myKey] : {infoWindowStatus:
{$set:true}}})
}
);
要求的整个组件是:
import React, { Component } from 'react';
import './css/App.css';
import './css/Custom.css';
import NeighborhoodMap from './neighborhoodMap';
import 'typeface-roboto';
import escapeRegEx from 'escape-string-regexp';
import update from 'immutability-helper';
class App extends Component {
state = {
locations : [
{
position: {lat: 41.3029876, lng: -72.9191306},
title: "Pepe's Pizza",
mappy: '',
infoWindowStatus: false,
key : 0,
infoWindow :
{
content : "Loading...",
contentUrl : ""
}
}
]
}
// TODO: separate data into external data file.
componentDidMount(){
this.setState({
filteredLocationsOnly : this.state.locations
})
}
// Launches Info Window on Google Map
showInfoWindowNow(locationSelected){
let myKey;
this.state.locations.filter( (location) =>{
if (locationSelected.name === location.title || locationSelected.title === location.title){
myKey = location.key;
return location
}
} );
this.updateInfoWindowContentAgain(myKey);
// // THIS CODE DOES NOT WORK AT ALL
// this.setState({ locations[myKey].infoWindowStatus : true })
// // THIS CODE DOESN'T SHOW THE INFO WINDOW
// console.log("Status: ", this.state.locations[myKey].infoWindowStatus);
// const tempLocations = [...this.state.locations];
// tempLocations[myKey] = { ...tempLocations[myKey], infoWindowStatus: true };
//
// this.setState(
// {
// locations: tempLocations
// }
// );
// console.log("Status Now: ", this.state.locations[myKey].infoWindowStatus);
// THIS DODGEY CODE WORKS
// https://stackoverflow.com/questions/51250518
this.state.locations[myKey].infoWindowStatus = true;
this.forceUpdate()
} //showInfoWindowNow
// Close Info Window on Google Map
closeInfoWindowNow(locationSelected){
this.forceUpdate()
}
// Update Content for Info Window
updateInfoWindowContentAgain(myKey){
return this.getInfoWindowContent(this.state.locations[myKey].title, myKey);
}
// Update Content for Info Window sub-function
getInfoWindowContent(searchTerm, myKey){
var nytAuthKey = "3d6801dab968446787ea71d5042ad8f7";
var myNewYorkTimesUrl = `https://api.nytimes.com/svc/search/v2/articlesearch.json?&api-key=${nytAuthKey}&q=${searchTerm}`
var contentForLocation;
var contentUrl;
let content = fetch(myNewYorkTimesUrl)
.then(response => response.json() )
.then(data => {
return addArticles(data);
}
)
.catch(error => requestError(error, 'articles'));
// add text from fetch request
function addArticles(data){
if (data.response && data.response.docs && data.response.docs.length > 1){
const articles = data.response.docs;
// var content, contentUrl;
let infoWindow = {};
articles.map(article => {
infoWindow.content = `${article.snippet}`;
infoWindow.contentUrl = `${article.web_url}`;
contentForLocation = `${article.snippet}`;
contentUrl = `${article.web_url}`;
return infoWindow;
});
}
} //addArticles
// Handle Errors
function requestError(error, part) {
console.log("Error: ", error);
}
content.then( content => {
this.state.locations[myKey].infoWindow.content = (contentForLocation);
this.state.locations[myKey].infoWindow.contentUrl = contentUrl;
this.forceUpdate()
}
)} // getInfoWindowContent
// end Nyt
filterLocations(query){
const match = new RegExp(escapeRegEx(query), 'i')
let showingLocations = this.state.locations.filter((location) => {
return match.test(location.title);
});
this.setState({
filteredLocationsOnly : showingLocations
})
} // end filterLocations
clearQuery = () => {
this.setState({query : ''});
}
updateQuery = (query) => {
this.setState({query : query.trim()})
this.filterLocations(query);
}
render() {
return (
<div className="App">
<NeighborhoodMap
menuOpen = {this.state.menuOpen}
locations = {this.state.locations}
filteredLocationsOnly = {this.state.filteredLocationsOnly}
query = {this.state.query}
updateQuery = { (query) => {
this.updateQuery(query)
}}
clearQuery = { () => {
this.clearQuery()
}}
filterLocations = { (query) => {
this.filterLocations(query)
}}
infoWindowStatus = {this.state.infoWindowStatus}
showInfoWindowNow = { (location) => {
this.showInfoWindowNow(location)
}}
closeInfoWindowNow = { (location) => {
this.closeInfoWindowNow(location)
}}
updateInfoWindowContentAgain = { (id) => {
this.updateInfoWindowContentAgain(id)
}}
infoWindow = {this.state.infoWindow}
/>
</div>
) // return
}// render
} // Component
export default App;
最佳答案
您可以跳过不变性助手,而复制locations
数组,创建locations[myKey]
副本,然后覆盖infoWindowStatus
:
const locations = [...this.state.locations];
locations[myKey] = { ...locations[myKey], infoWindowStatus: true };
this.setState({ locations });
另外,您赋予
infoWindowStatus
的NeighborhoodMap
来自this.state.infoWindowStatus
,但是将其存储在this.state.locations[0].infoWindowStatus
中。关于javascript - 使用this.setState和来自immutability-helper的更新不会重新渲染React组件,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/51250518/