在React-Router中未定义的React上下文值

时间:2019-08-20 10:28:44

标签: reactjs react-router react-context

我正在尝试将context api与react-router一起使用。我有一个容器,其中包含mapStateToProps的trackList属性中的歌曲列表,我想使用上下文api将其传递给名为TrackDetail的无状态组件(无react-redux)。正如您将在下面看到的那样,我使用了useContext钩子和render props模式,但没有成功从上下文中获取该值。

这是“路线”文件中的内容:

import React, { Component } from "react";
import { BrowserRouter as Router, Route, Switch, Redirect } from "react-router-dom";
import TrackList from "../../containers/TrackList/TrackList";
import TrackDetail from "../TrackDetail/TrackDetail";

class Routes extends Component {
  render() {
    return (
      <div className="Routes">
        <Router>
          <Switch>
            {this.props.children}
            <Route path="/tracks" component={TrackList} exact />
            <Route path="/tracks/:id" component={TrackDetail} exact/>
            <Route exact path="/" render={() => (<Redirect to="/tracks" />)} />
            <Route path="*" render={() => (<Redirect to="/tracks" />)} />
          </Switch>
        </Router>
      </div>
    );
  }
}

export default Routes;

这是我的TrackList.jsx容器(已连接到redux):

import React, { Component } from "react";
import { connect } from "react-redux";
import "./TrackList.scss";
import Spinner from "../../components/shared/Spinner/Spinner";

export const TrackListContext = React.createContext();

class TrackListProvider extends Component {

  state = {
    foo: "bar"
  }

  render() {
    return (
      <TrackListContext.Provider value={this.state}>
        {this.props.children}
      </TrackListContext.Provider>
    )
  }
};

export class UnConnectedTrackList extends Component {
  constructor(props) {
    super(props);
    this.state = {
      value: ""
    };
  }

  componentDidMount() {
    if (this.props.trackList.length === 0) {
      this.props.getTracks()
      .then(()=>this.props.changeSpinnerState());
      
    }
  }

  render() {
    if (this.props.spinnerState) return <Spinner />;
    return <TrackListProvider trackList={this.props.trackList}>
    <div>
    more content
    </div>
    </TrackListProvider>;
    
  }
}

const mapStateToProps = state => {
  const trackList = state.trackList.length !== 0 ? state.trackList : [];
  return {
    trackList,
  };
};
export default connect(
  mapStateToProps,
  null
)(UnConnectedTrackList);

这是我的TrackDetail.jsx:

import React, { useContext } from "react";
import {TrackListContext} from '../../containers/TrackList/TrackList';
import "./TrackDetail.scss";

const TrackDetailCmp = (props) => {
  const value = useContext(TrackListContext);
  // value is undefined
  const currentTrackIndex = 0;
  const { trackList} = props;
  // trackList is undefined

  return (
    <div className="container">
      <h3></h3>
    </div>
  );
};

const withContext = (Component) => {
  return (props) => <TrackListContext.Consumer>
  {(value) => <Component {...props} trackList={value} />}
  </TrackListContext.Consumer>
};

const TrackDetail = withContext(TrackDetailCmp);
export default TrackDetail;

但是我不确定。

版本可能有问题。

这是我的package.json:

{
  
  "dependencies": {
    "react": "^16.9.0",
    "react-dom": "^16.9.0",
    "react-redux": "^7.1.0",
    "react-router": "^5.0.1",
    "react-router-dom": "^5.0.0",
    "redux": "^4.0.4",
    "redux-thunk": "^2.3.0"
  },
  "devDependencies": {
    "@types/jest": "^24.0.17",
    "@types/react": "^16.9.2",
    "enzyme": "^3.10.0",
    "enzyme-adapter-react-16": "^1.14.0",
    "node-sass": "^4.12.0"
  }
}

1 个答案:

答案 0 :(得分:0)

首先要提到的是,React Router在这里不会影响任何东西,因为它只决定渲染哪些组件。

接下来要使上下文起作用,上下文使用者必须是上下文提供者的子级。正如我在这里看到的那样,上下文提供者是“ TrackList”组件,使用者是“ Track”组件,但是它们是同级元素(而且当您将交换机与React Router一起使用时,将仅呈现一条路由,因此您甚至无法将它们呈现为同级)。

我会尝试将整个路由器包装在上下文提供程序中,并且除了提供反应列表的上下文之外,我看不到其他用法,因此我将其删除。您最终会得到这样的东西:

/Users/Shared/Jenkins

然后在您的曲目列表组件中,我将删除HOC(您不想同时做两件事)。最后,上下文给出的结果是值,这意味着您将提供者的值设置为sudo launchctl unload /Library/LaunchDaemons/org.jenkins-ci.plist sudo mkdir -p /Users/Shared/Jenkins/Home sudo chown -R daemon /Users/Shared/Jenkins sudo launchctl load /Library/LaunchDaemons/org.jenkins-ci.plist ,因此消费者将收到该完整对象。结果应如下所示:

class Routes extends Component {
  render() {
    return (
      <TrackListProvider value={{trackList: this.props.trackList}}>
          <div className="Routes">
            <Router>
              <Switch>
                {this.props.children}
                <Route path="/tracks/:id" component={TrackDetail} exact/>
                <Route exact path="/" render={() => (<Redirect to="/tracks" />)} />
                <Route path="*" render={() => (<Redirect to="/tracks" />)} />
              </Switch>
            </Router>
          </div>
        </TrackListProvider>
    );
  }
}