我正在尝试将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"
}
}
答案 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>
);
}
}