简体   繁体   中英

React: How to properly update state of parent component after changing child component

I'm new to React and was wondering if I could get some advice here.

I currently am using Mapbox and have map coordinates set to Manhattan along with a description about the city. I would like the descriptions and the location of the map to change every time a user presses a button (eg the map would move to Brooklyn upon the user clicking)

Essentially, I am trying to build this: https://docs.mapbox.com/mapbox-gl-js/example/playback-locations/ , but where the neighborhoods slide over only to button clicks. I wasn't sure how I could move this vanilla Javascript and html into React, so I tried to recreate the best I can.

My code is as follows. I'm aware that the child is a class component and the parent is a function component.

Parent Component

const locations = [
  {
    'id': '1',
    'title': 'Manhattan',
    'description': 'The capital of culture, finance, entertainment, and fashion. Need we say more?',
    'camera': {center: [-74.007, 40.7437], bearing: 25.3, zoom: 11.5}
  },
  {
    'id': '2',
    'title': 'Bronx',
    'description': "A fantastic zoo and botanical garden. Not to mention the birthplace of hip-hop!",
    'camera': {center: [-73.8709, 40.8255], bearing: 0, zoom: 12.21}
  },
  {
    'id': '3',
    'title': 'Brooklyn',
    'description': "This borough is experiencing a renaissance and continues to bring new surprises.",
    'camera': {center: [-73.9499, 40.626], bearing: -8.9, zoom: 11.68}
  },
  {
    'id': '4',
    'title': 'Queens',
    'description': "Experience one of the world's most diverse places!",
    'camera': {center: [-73.8432, 40.6923], bearing: 36, zoom: 11.37}
  },
  {
    'id': '5',
    'title': 'Staten Island',
    'description': 'A great place for family and friends with a stunning view, tons of parks, and a free ferry ride!',
    'camera': {center: [-74.1991, 40.5441], bearing: 28.4, zoom: 11.64}
  },
  {
    'title': 'Five Boroughs of New York',
    'description': 'New York City is made up of five boroughs: Bronx, Brooklyn, Manhattan, Queens and Staten Island. Each one has its own attractions-not to mention data!',
    'camera': {center: [-74.0315, 40.6989], zoom: 9.68, bearing: 0, pitch: 0}
  }
];


function Neighborhood() {
  const [count, setCount] = useState(0);
  const borough = <Boroughs data={locations[count]}/>
  const [map, setMap] = useState(borough); 

  function increase() {
    setCount(count+1);
    setMap(<Boroughs data={locations[count]}/>);
  }

  function decrease() {
    setCount(count-1);
    setMap(<Boroughs data={locations[count]}/>);
  }

  return (
    <div className="all-neighborhoods">
      <PageNavbar active="Listing" />
      <header className="App-header">
      </header>
      {count}
      <button onClick={decrease}>-</button>
      <button onClick={increase}>+</button>
      <div className="container-fluid">
        <div className="row d-flex flex-fill min-vh-100">
          {map}
        </div>
      </div>
    </div>
  );
}

export default Neighborhood; 

Child Component

mapboxgl.workerClass = MapboxWorker;
mapboxgl.accessToken = '<hidden>';
 
export default class Boroughs extends React.PureComponent {
  constructor(props) {
    super(props);
    this.state = {
      title: this.props.data.title,  
      description: this.props.data.description,
      lat: this.props.data.camera.center[0],
      long: this.props.data.camera.center[1],
      zoom: this.props.data.camera.zoom,
      bearing: this.props.data.camera.bearing
    }
    this.mapContainer = React.createRef();
  }

  componentDidMount() {
    const { lat, long, zoom, bearing } = this.state;
    const map = new mapboxgl.Map({
      container: this.mapContainer.current,
      style: 'mapbox://styles/mapbox/streets-v11',
      center: [parseFloat(lat), parseFloat(long)],
      maxZoom: 16,
      minZoom: 9,
      zoom: parseFloat(zoom),
      bearing: parseFloat(bearing),
      pitch: 50 
    });
  }

  render() {
    const { title, description } = this.state;
    return (
      <div ref={this.mapContainer} className="map-container flex-grow-1">
        <div className="map-overlay-container">
          <div className="map-overlay">
            <h2 id="location-title">{title}</h2>
            <p id="location-description">{description}</p>
          </div>
        </div>
      </div> 
    );
  }
}

Try reading up on the React Context API . Anything that is wrapped within the context provider will be exposed to the states of the context

It's not advisable for the child to change the state of the parent component. There is this hack though, Add a function in the parent that updates the state, pass it to the child as a prop and call it every time a change happens in the child component.

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