在React子家长组件中将道具转移到多级向上

时间:2018-07-28 22:35:27

标签: javascript reactjs

我有3个具有这种关系的React组件:

  1. 父母
  2. 孩子
  3. ChildofChild

单击以更新ChildofChild组件中的状态时,我想在Parent组件中有一个按钮。我可以通过道具将其发送到Child组件,并在其中运行功能。

ChildOfChild

// ChildOfChild Component
export class PlaceInfoWindow extends Component {

  render() {
    const {description, name, price} = this.props

    return(
      <InfoWindow onCloseClick={this.props.closeWindow}>
        <div>
          <h1>{name}</h1>
          <p>{description}</p>
          <span>${price}</span>
          <button type="button" onClick={this.props.onAdd} className="btn btn-primary btn-success m-2">Add</button>
        </div>
      </InfoWindow>
    );
  }
}

export default PlaceInfoWindow

孩子

//Child Component
    export class PlaceMarker extends Component {
      constructor(props) {
        super(props);

        this.state = {
          showTooltip: false,
        };
      }

      clickTooltip() {
        this.setState({ showTooltip: !this.state.showTooltip });
      }

      closeWindow() {
        this.setState({ showTooltip: false });
      }

       render() {
        const { showTooltip } = this.state;
        const { lat, lng, name, price, description } = this.props;

        return (
          <Marker
            position={{
              lat: parseFloat(lat),
              lng: parseFloat(lng)
            }}
            onClick={this.clickTooltip.bind(this)}
            icon="https://image.ibb.co/cGPSW8/red_marker.png"
          >
            {showTooltip && (
              <PlaceInfoWindow
                description={description}
                name={name}
                price={price}
                closeWindow={this.closeWindow.bind(this)}
                onAdd={this.props.onAdd}
              />
            )}
          </Marker>
        );
      }
    }

    export default PlaceMarker;

父母

// Parent Component
const AirbnbMap = withGoogleMap(props => (
  <GoogleMap
    defaultCenter={props.center}
    defaultZoom={props.zoom}
    defaultOptions={{
      styles: userMapStyle
    }}
  >
    {props.places.length > 0 &&
      props.places.map(place => (
        <PlaceMarker
          key={`place${place.id}`}
          id={place.id}
          lat={place.latitude}
          lng={place.longitude}
          description={place.description}
          name={place.name}
          price={place.price}
          onAdd={this.handleAdd}
        />
      ))}
  </GoogleMap>
));

export class Map extends Component {
  constructor(props) {
    super(props);

    this.zoom = 7;

    this.state = {
      lat: 50.0515918,
      lng: 19.9357531,
      places: [       
        {
        id: 1,
        latitude: 50,
        longitude: 20,
        description: "ABC",
        name: "City",
        price: 20
      }]
    };
  }


  handleAdd = () => {
    console.log("handle add called");
  };

  render() {
    const { lat, lng, places } = this.state;
    console.log(places);
    return (
      <div style={{ width: `100%`, height: `750px` }}>
        <AirbnbMap
          center={{
            lat: lat,
            lng: lng
          }}
          places={places}
          zoom={this.zoom}
          containerElement={<div style={{ height: `100%` }} />}
          mapElement={<div style={{ height: `100%` }} />}
        />
      </div>
    );
  }
}

export default Map;

但是如何将其发送到Parent(两个级别)组件?这样,Child组件将仅将道具从其子对象(Parent获取的ChildofChild组件转发。

3 个答案:

答案 0 :(得分:2)

仅转发道具没有问题。这包括处理程序:

class Parent extends Component {
    handle = event => { /* handle event */ };

    render() {
        return (
            <Child handler={this.handle} />
        );
    } 
}

const Child = ({handler}) => (
    <ChildOfChild handler={handler} />
);

const ChildOfChild = ({handler}) => (
    <button onClick={handler}>Click me!</button>
);

答案 1 :(得分:0)

您的顶级Parent组件不是AirbnbMap,而是Map类。另外,您在Map类中声明了handleAdd,但没有将其传递给Airbnb组件。在地图上,您应该将其传递给:

{
  "comments": {
    "5a6efb94b0e8c36f99fba019": {
      "id": "5a6efb94b0e8c36f99fba019",
      "message": "Alias quod est voluptatibus aut quis sunt aut numquam."
    },
    "5a6efb94b0e8c36f99fba01b": {
      "id": "5a6efb94b0e8c36f99fba01b",
      "message": "Harum quia asperiores nemo."
    },
    "5a6efb94b0e8c36f99fba01c": {
      "id": "5a6efb94b0e8c36f99fba01c",
      "message": "Vel veniam consectetur laborum."
    },
    "5a6efb94b0e8c36f99fba01e": {
      "id": "5a6efb94b0e8c36f99fba01e",
      "message":
        "Possimus beatae vero recusandae beatae quas ut commodi laboriosam."
    }
  },
  "blogPosts": {
    "5a6efb94b0e8c36f99fba016": {
      "id": "5a6efb94b0e8c36f99fba016",
      "title": "Dolorem voluptatem molestiae",
      "comments": [
        "5a6efb94b0e8c36f99fba019",
        "5a6efb94b0e8c36f99fba01b",
        "5a6efb94b0e8c36f99fba01c",
        "5a6efb94b0e8c36f99fba01e"
      ]
    }
  },
  "users": {
    "5a6efb94b0e8c36f99fba013": {
      "id": "5a6efb94b0e8c36f99fba013",
      "email": "Lloyd.Nikolaus@yahoo.com",
      "posts": ["5a6efb94b0e8c36f99fba016"]
    }
  }
}

然后在AirbnbMap类上:

<AirbnbMap handleAdd={this.handleAdd}
    // Rest of props here
    />

其余的看起来还可以。

答案 2 :(得分:0)

从React 16.3开始,您可以使用新的Context API,因此您无需将道具传递给每个孩子,并且可以轻松整洁地举起状态。

import React, { Component, createContext } from 'react';

const ParentContext = createContext({});

class Parent extends Component {
    handle = event => { console.log('Event', event) };

    render() {
        return (
          <ParentContext.Provider value={{
            onClick: this.handle,
          }}>
            <Child />
          </ParentContext.Provider>
        );
    } 
}

const Child = () => (<ChildOfChild />);

const ChildOfChild = () => ( 
  <ParentContext.Consumer>
    { (context) => <button onClick={context.onClick}>Click me!</button>}
  </ParentContext.Consumer>
);

export default Parent;