【发布时间】:2019-11-05 02:49:49
【问题描述】:
我正在尝试使用 React Hooks 重构我的代码,但我真的不明白如何使用 Hooks 通过 React 路由器将 props 传递给我的组件。
旧的(正常的)React 代码如下所示:
App.js
import React from 'react';
import { withRouter } from "react-router-dom";
import {Routes} from './routes/Routes';
function App() {
const childProps={something: "else"};
return (
<div className="App">
<Routes childProps={childProps} />
</div>
);
}
export default withRouter(App);
Routes.js
import {Switch, Route} from 'react-router-dom';
import Game from '../game/Game';
import Scenario from '../game/Scenario';
const CustomRoute = ({ component: C, props: cProps, ...rest }) =>
<Route
{...rest}
render={(props) =>
<C {...props} {...cProps} />
}
/>;
export const Routes = ({childProps}) =>
<Switch>
<Route path="/" exact component={Game} props={childProps} />
<CustomRoute path="/scenario/:id" exact component={Scenario} props={childProps}/>
</Switch>
Game.js
import React from 'react';
const Game = () => {
return (
<div className="Game">
<header className="Game-header">
<a href="/scenario/0">
START
</a>
</header>
</div>
);
};
export default Game;
Scenario.js
export default class Scenario extends Component {
constructor(props) {
super(props);
this.state = {
scenarios: null,
scenarioId: null,
currentScenario: null
}
}
async componentDidMount() {
const scenarioId = await this.props.match.params.id;
const scenarios = await data.scenarios;
this.setState({scenarios, scenarioId});
this.getScenario();
}
getScenario = () => {
this.state.scenarios.forEach((scenario) => {
if (scenario.id === this.state.scenarioId) {
const currentScenario = scenario;
this.setState({currentScenario});
}
})
}
render() {
return (
<div>
{this.state.currentScenario != null
? this.state.currentScenario.options.length === 1
? (
<div>
<div>{this.state.currentScenario.text}</div>
<div>{this.state.currentScenario.options[0].text}</div>
<a href="/">Go Back</a>
</div>
)
: (
<div>
<div>{this.state.currentScenario.text}</div>
<div>{this.state.currentScenario.options.map((option, index) => (
<div key={index}>
<a href={`/scenario/${option.to}`}>
{option.text}
</a>
</div>
))}</div>
</div>
)
: null
}
</div>
);
}
};
所以我在网上找到了这段代码,它会改变我从路由器获取道具的方式:
HookRouter.js
import * as React from 'react';
import { BrowserRouter, Route } from 'react-router-dom';
const RouterContext = React.createContext(null);
export const HookedBrowserRouter = ({ children }) => (
<BrowserRouter>
<Route>
{(routeProps) => (
<RouterContext.Provider value={routeProps}>
{children}
</RouterContext.Provider>
)}
</Route>
</BrowserRouter>
);
export function useRouter() {
return React.useContext(RouterContext);
};
新的 App.js
import React from 'react';
import { withRouter } from "react-router-dom";
import {Routes} from './routes/Routes';
import {HookedBrowserRouter, useRouter} from './routes/HookRouter';
function App() {
const childProps={something: "else"};
return (
<HookedBrowserRouter>
<div className="App">
<Routes childProps={childProps} />
</div>
</HookedBrowserRouter>
);
}
export default withRouter(App);
我在新的 Scenario.js 中得到了他的帮助
import React, { Component, useState, useEffect } from 'react';
import data from '../data/fake';
import {useRouter} from '../routes/HookRouter';
const RouterContext = React.createContext(null);
const HookSceneario = () => {
const [scenarios, setScenarios] = useState(null);
const [scenarioId, setScenarioId] = useState(null);
const [currentScenario, setCurrentScenario] = useState(null);
// Similar to componentDidMount and componentDidUpdate:
// Update the document title using the browser API
// console.log(React.useContext(RouterContext));
useEffect(() => {
console.log(scenarios);
});
return (
<div>
// ...
</div>
);
}
所以useState 替换了类构造函数中的this.state,useEffect 应该替换componentDidMount,但我找不到从路由器获取props 的方法。
【问题讨论】:
-
<Scenario/>的孩子是否需要routeProps?因为你这样做的方式,因为场景是由<Route>组件呈现的,而你在render={(routeProps) => <C {...routeProps)/>中传递routeProps。请注意,我已重命名为routeProps,以明确render道具中可用的props对象是routeProps(匹配、位置和历史记录)。因此<Scenario/>已经可以访问routeProps。 -
感谢@cbdev420 的建议。所以你是写那段代码的人。我的问题是如何将
Scenario中的这些道具称为带有 Hooks 的函数。看来我不能console.log任何道具,比如类。 -
我认为异步生命周期方法是个坏主意...我可以制作单独的异步函数并将这个逻辑移到那里。然后你在 componentdidmount 中调用这个函数,比如 getScenario
-
@Bonjov 谢谢你的建议。除非我误解了您的评论,否则上面的代码似乎符合您的建议:在 componentDidMount 中调用异步函数。
标签: javascript reactjs react-router react-hooks