如何在与上下文反应时设置兄弟组件的状态?

时间:2020-03-25 14:38:04

标签: javascript reactjs

我想用onClick设置同级组件的状态。同级组件是 map.js 中的 Kartta sidebar.js 中的侧边栏。我在 Kartta 中拥有一个函数fetchAll(),该函数可以更改状态并在传单地图上创建标记。我想通过点击 Search 按钮从边栏调用该函数。我尝试使用上下文和道具来实现,但是失败了。有一个更好的方法吗?我很新来做出反应,非常感谢您的帮助。谢谢。

index.js(父级)

import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import './css/main.css';
import 'bootstrap/dist/js/bootstrap.bundle.js';
import 'leaflet/dist/leaflet.css';
import { Kartta } from './components/map';
import Sidebar from './components/sidebar';
import Navbar from './components/navbar';

class App extends Component {
    constructor(props) {
        super(props);
    }

    componentDidMount = () => {

    }

    render() {
        console.log(this.state);
        return (
            <div id="main-container" className="container-fluid h-100 p-0">
                <Navbar />
                <div id="container0" className="row h-100 w-100 m-0 wrapper">
                    <Sidebar />
                    <div id="container02" className="col h-100 w-100 p-0">
                    <Kartta />
                    </div>
                </div>
            </div>
        );
    }
}

ReactDOM.render(<App />, document.getElementById('root'));

map.js(同级1)

import React, { Component, createContext } from 'react';
import L from 'leaflet';
import { Map, Marker, Popup, TileLayer } from 'react-leaflet';

const position = [62.241581, 25.758742];

export const MapContext = createContext();

export class Kartta extends Component {
  constructor(props) {
    super(props);
    this.state = {
        places: []
    };
    this.fetchAll = this.fetchAll.bind(this);
  }

  componentDidMount() {

  }

  fetchAll = () => {
    console.log("täällä");
    fetch('test.json')
    .then(res => res.json())
    .then((data) => {
        this.setState({ places: data })
    })
    .catch(console.log(this.state.places))
  }

  iconSize = (iconName) => {
    if (iconName == 'tree.png') {
      return 30, 30
    }
    else {
      return 15, 30
    }
  }

  MapComponent = () => {
    if(this.state.places.length > 0){
      return (
        <Map center={position} zoom={7}>
          <button onClick={this.haeKaikki}>Hae</button>
            <TileLayer
              url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
              attribution="&copy; <a href=&quot;http://osm.org/copyright&quot;>OpenStreetMap</a> contributors"
            />
            {this.state.kohteet.map((kohde) => (
                <Marker key={'key' + kohde.id} position={[kohde.lon, kohde.lat]} icon={
                    new L.Icon({
                        iconUrl: require('../img/' + kohde.icon),
                        iconSize: new L.Point(this.iconSize(kohde.icon)),
                        id: kohde.id + kohde.icon
                    })
                }>
                    <Popup>
                        <h1>{kohde.name}</h1>
                        <p>{kohde.desc}</p>
                    </Popup>
                </Marker>
              ))}

          </Map>
      )
    }
    else {
      return (
        <Map center={position} zoom={7}>
          <button onClick={this.haeKaikki}>Hae</button>
            <TileLayer
              url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
              attribution="&copy; <a href=&quot;http://osm.org/copyright&quot;>OpenStreetMap</a> contributors"
            />
          </Map>
      )
    }
  }

  render() {
      return (
        <MapContext.Provider value = {{
          state: this.state,
          update: this.fetchAll
        }}>
          <div id="mapid" className="h-100 w-100">
            <this.MapComponent />
          </div>
        </MapContext.Provider>
      )
  }
}

export const MapConsumer = MapContext.Consumer;

sidebar.js(同级2)

import React, { Component } from 'react';
import { MapConsumer } from './map';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faInfoCircle } from '@fortawesome/free-solid-svg-icons';

class Sidebar extends Component {
    constructor(props) {
        super(props);
        this.state = {
            kohteet: []
        };
       }

    componentDidMount = () => {

    }

    handleClick = (e) => {
        e.preventDefault();
    }

    render() {
        return (
            <div className="p-2 collapse in" id="sidebar">
                <div className="list-group panel" id="sidebar-div0">
                    <form id="sidebar-form0">
                        <div id="sidebar-div01" className="form-group active">

                            <label id="sidebar-label0" htmlFor="exampleInputEmail1">Kohteen nimi</label><span> </span>
                            <FontAwesomeIcon icon={faInfoCircle} className="pointer dropdown-toggle" data-toggle="dropdown" alt="Hakuohjeet" />
                            <div id="search-info" className="p-2 dropdown-menu dropdown-menu-right">
                                <p>Hae kirjoittamalla tägejä</p>
                            </div>
                            <div className="row">
                                <div className="col-7 ml-3 p-0">
                                    <input type="text" className="form-control" id="searchByName" aria-describedby="emailHelp" placeholder="Syötä kohteen nimi" />
                                </div>
                                <button id="sidebar-button0" type="submit" className="btn btn-primary ml-2 col-3" onClick={this.handleClick}>Search</button>
                            </div>

                        </div>
                    </form>
                    <div id="sidebar-div02" className="dropdown">
                        <a id="sidebar-button1" className="btn btn-light dropdown-toggle p-0 thaku" type="button" data-toggle="dropdown">Tarkennettu haku
                        <span id="sidebar-span0" className="caret"></span></a>
                        <div id="sidebar-div020" className="p-0 dropdown-menu border-0 mt-2 w-100 h-100">
                            <form id="sidebar-form1">
                                <div id="sidebar-div0200" className="form-group p-0">
                                    <label id="sidebar-label1" htmlFor="exampleInputEmail1">Paikkakunta</label>
                                    <input id="sidebar-input1" type="text" className="form-control" placeholder="Syötä paikkakunta" />
                                </div>
                                <div id="ch-div0" className="row pl-3">
                                    <label id="lbl-location">Sijainti</label>
                                    <input id="ch-location" className="mt-2 ml-2" type="checkbox" aria-label="Checkbox for following text input" />
                                </div>
                                <div className="input-group mb-3">
                                <div className="input-group-prepend">
                                    <label className="input-group-text" htmlFor="inputGroupSelect01">Palvelut</label>
                                </div>
                                    <select className="custom-select" id="inputGroupSelect01">
                                        <option defaultValue>Valitse...</option>
                                        <option value="1">Kakkapaikka</option>
                                        <option value="2">Pissapaikka</option>
                                        <option value="3">Kaljapaikka</option>
                                    </select>
                                </div>
                                <div id="dropdown-div3" className="row p-0">
                                    <button id="sidebar-dropdown-button0" type="submit" className="ml-3 btn btn-primary">Tarkennettu haku</button>
                                </div>
                            </form>
                        </div>
                    </div>
                </div>
        </div>
        );
    }
}

export default Sidebar;

1 个答案:

答案 0 :(得分:1)

如果您想对同级组件产生某些影响,则有一些解决方案:

  1. 使用Redux-

  2. 通过属性将值传递给Parent,然后更改Parent的状态,然后将值从Parent状态传递给同级组件。例如:Child1元素->父级-> Child2元素。

父元素

    class Parent extends Component {
        constructor(props) {
            super(props);
            this.state={
                valueToChild2:null
            }
        }

        getValueFromChild1=(value)=>{
            if(this.state.valueToChild2 !== value)
            {
                this.setState({
                    valueToChild2:value
                })
            }
        }

        render() {

            return (
                 <div>
                     <Child1 getValueFromChild1={this.getValueFromChild1} />
                     <Child2 passValueToChild2={this.state.valueToChild2}/>
                 </div>
            );
        }
    }

Child1元素:

    class Child1 extends Component {
        constructor(props) {
            super(props);

        }

        sendValueToParent=()=>{
            let msg="Hello"
            this.props.getValueFromChild1(msg)
        }

        render() {

            return (
                 <div onClick={this.sendValueToParent}>
                 </div>
            );
        }
    }

Child2元素:

    class Child2 extends Component {
        constructor(props) {
            super(props);
            this.state={
                value:null
            }
        }

        componentDidMount(){
            if(this.props.passValueToChild2)
            {
                this.setState({
                    value:this.props.passValueToChild2
                })
            }
        }

        componentDidUpdate(){
            if(this.props.passValueToChild2)
            { 
                if(this.props.passValueToChild2 !== this.state.value)
                {
                    this.setState({
                        value:this.props.passValueToChild2
                    })
                }
            }       
        }

        render() {

            return (
                 <div>
                 </div>
            );
        }
    }