我如何才能使props.match.params.id可以访问任何子组件?

时间:2017-07-27 15:48:33

标签: reactjs parameters scope react-router

我目前正试图围绕如何构建ReactJS应用程序。以下是相关信息:

开发环境:npm,webpack

依赖关系:React,ReactDOM,React路由器,React路由器DOM

代码 :(稍微澄清一下,不要透露更多敏感信息。)

/***********
TABLE OF CONTENTS
01.0.0 - Imports
02.0.0 - Data
03.0.0 - Components
03.1.0 -- Base
03.2.0 -- Location
03.3.0 -- Main
03.3.2 --- Map
04.0.0 - Render
***********/

/* 01.0 Imports */
import React from 'react';
import ReactDOM from 'react-dom';
import $ from 'jquery';
import {
  HashRouter,
  Route,
  Switch,
  Link
} from 'react-router-dom';

console.log("Set-up successful");
/* 02.0 Data */
const locationDataArray = {
  locations: [
    {
      "location": "Scenario A",
      "slug": "lipsum",
      "googleUrl": "https://www.google.com/maps/place/Central+Park/@40.7828687,-73.9675438,17z/data=!3m1!4b1!4m5!3m4!1s0x89c2589a018531e3:0xb9df1f7387a94119!8m2!3d40.7828647!4d-73.9653551",
      "mapUrl": "locations/scenA/main-map.png",
      "areaMaps": [
        {
          "name": "Overall",
          "url": "inner/map-overall.html"
        }, {
          "name": "A",
          "url": "inner/map-a.html"
        }, {
          "name": "B",
          "url": "inner/map-b.html"
        }
      ],
      "overallPDF": "diagram.pdf",
      "mapKey": "mapkey.txt",
      "mapImagemap": "imagemap.txt"
    } // list truncated for your convenience.
  ],
  all: function() {return this.locations},
  get: function(id) {
    const isLocation = q => q.slug === id
    return this.locations.find(isLocation)
  }
}

/* 03.0 Components */
/* 03.1 Base */
class App extends React.Component {
  constructor() {
    super();
    console.log("<App /> constructor locationDataArray: " + locationDataArray);
    this.state = {
      locationData: locationDataArray,
      test: 'testing!'
    };
  }
  render() {
    console.log("<App /> locationDataArray: " + locationDataArray);
    console.log("<App /> state, testing: " + this.state.test);
    return(
      <div>
        <Switch>
          <Route exact path='/' component={LocationGrid} />
          <Route path='/locations/:id' component={MainMap}/>
        </Switch>
      </div>
    );
  }
}

/* 03.2.0 -- Location */

class LocationGrid extends React.Component {
  constructor() {
    super();
  }
  render() {
    return(
      <div>
        <h2>Location Grid</h2>
        <div>
          <Link to="/locations">Main Map</Link>
        </div>
        <div>
          <ul>
            { // this part works with extra items in locationDataArray.
              locationDataArray.all().map(q => (
                <li key={q.slug}>
                  <Link to={`locations/${q.slug}`}>{q.location}</Link>
                </li>
              ))
            }
          </ul>
        </div>
      </div>
    );
  }
}

/* 03.3.0 -- Main */

class MainMap extends React.Component {
  constructor(props) {
    super();
    console.log("Main map is on");
    const location = locationDataArray.get(
      props.match.params.id
    );
    if (!location) {
      console.log("No such location!");
    }
    if (location) {
      console.log("These tests show that the locationDataArray is accessible from this component.");
      console.log("A: props.match.params.id is: " + props.match.params.id);
      console.log("B: Location is: " + location.location);
      console.log("C: Map URL: " + location.mapUrl);
      console.log("State is: " + location);
    }
  }
  render() {
    return (
      <div>
        <MapHolder />
      </div>
    );
  }
}

/* 03.3.2 --- Map */
//var mapUrl = require(location.mapUrl);
class MapHolder extends React.Component {
  render() {
    console.log("And these tests show that the locationDataArray is NOT accessible from this component.");
    console.log("1. Map location test, mapUrl: " + location.mapUrl);
    console.log("2. Map location test, slug: " + location.slug);
    return <div>
      <img id="imagemap" className="map active" src={location.mapUrl} width="1145" height="958" useMap="#samplemap" alt="" />
      <map name="samplemap" id="mapofimage">
         <area target="" alt="1" title="1" href="inner/01.html" coords="288,356,320,344,347,403,315,420" shape="poly"></area>
         {/* Additional imagemap areas. Truncated for your conveinence.*/}
      </map>
      <p>A map would be here if I could figure out the bug.</p>
      </div>
  }
}

/* 04.0.0 -- Render */

ReactDOM.render((
  <HashRouter>
    <App />
  </HashRouter>
), document.getElementById('container'));
如果需要,

package.jsonwebpack.config.js都在git repository

总体目标:我想通过React Router路由参数和JSON对象动态地向主要组件和子组件提供信息。本质上,我希望能够将param与对象中的项相关联,以便组件可以引用类似arrayItem.itemProperty的东西,并且它可以动态工作。

我试图尽可能远离Redux,因为我现在已经被React轻微压倒了。

当前问题

数组(第26-55行)在代码中,但是1个组件(<MainMap />,第113-138行)之外的任何内容都无法访问它。

其中一个子组件的示例是<MapHolder />,它位于第142-156行。 (在这些情况下,我得到ReferenceError: props is not defined。)

我如何才能使props.match.params.id(或任何其他可以使这项工作的东西)可以访问任何子组件?

注意:我很清楚代码并不完美。但是这仍处于早期生产阶段,所以我想解决这个问题,希望其余的因此会清理。)

2 个答案:

答案 0 :(得分:0)

当您使用导入/导出时,模块之间不会共享全局变量。这是一件好事,但您可以从模块中导出多个变量。例如,您可以在App.js中export locationDataArray;从其他模块访问它,而不会破坏该模块的现有导出和导入。话虽如此,你几乎从不想在React中分享全局数据。作为一般经验法则,您应该将组件所依赖的数据“提升”到需要的树中的最高组件(如果您愿意,您甚至可以创建额外的父组件以使此组合更容易)。

当子组件依赖于来自父组件数据的部分数据时,通常应该通过props从父组件传递数据子集。使用给定location的实际地图数据向MapHolder添加id道具,而不是让组件查找id本身。然后在MapHolder的父级中,将其渲染为:

<MapHolder 
  location={locationDataArray.locations.find(location => location.slug === ID)}
  />

答案 1 :(得分:-1)

您正在寻找的是React's Context功能。它非常低级,是一个不稳定的API,可能在任何时候发生变化。含义:谨慎使用。

  

在某些情况下,您希望通过组件树传递数据,而不必在每个级别手动传递道具。您可以使用强大的&#34; context&#34;直接在React中执行此操作。 API。

TL; DR:

首先,声明孩子可以访问的上下文对象的形状,并实现getChildChildContext实际返回它:

class MyComponent extends React.Component {
  ...
  static childContextTypes = {
    foo: PropTypes.string // or whatever you have
  };

  getChildContext() {
    return {foo: "some value"};
  }
  ...
}

然后,当您想要访问子组件中的上下文时,通过在子组件上声明contextTypes来声明您希望这样做:

class SomeChildComponent extends React.Component {
  static childContextTypes = {
    foo: PropTypes.string
  };

  render() {
    // use in your component by accessing this.context.foo
  }
}

如果觉得笨拙,那是因为它的意思是:

  

绝大多数应用程序不需要使用上下文。

     

如果您希望应用程序稳定,请不要使用上下文。它是一个实验性的API,很可能会在未来的React版本中破解。

使用状态管理库(例如reduxmobx)来管理可从任意组件访问的状态,可能会获得更好的结果。