我了解如何使用state
和componentDidMount()
来获得微调器屏幕,但是我将如何在所有路径之间创建一个加载屏幕,而不必在每条路由中都写componentDidMount()
组件?
我的app.js文件
class App extends Component {
constructor(props) {
super(props);
this.child = React.createRef();
}
onWaypoint = () => {
this.child.current.navChangeHandler();
}
render() {
let routes = (
<Switch>
<Route exact path="/projects" component={Projects} />
<Route exact path="/about" component={About} />
<Route exact path="/gallery" component={Gallery} />
<Route exact path="/" component={Home} />
<Redirect exact to="/" />
</Switch>
)
return (
<BrowserRouter>
<div className="App" styleName="main-wrapper">
<Layout>
{routes}
<Navigation ref={this.child} />
</Layout>
</div>
</BrowserRouter>
);
}
}
我希望能够在这些路线之间看到一个微调器。
答案 0 :(得分:1)
您可以在子组件上创建HOC包装函数。然后,如果需要,您可以将HOC方法传递给子级,然后让该子级调用该方法。
例如:
父母:
export default WrappedComponent => {
class Wrapper extends Component {
state = { isLoading: true };
componentDidUpdate = prevProps => {
if (this.props.location !== prevProps.location) {
this.setState({ isLoading: true });
}
};
doneLoading = () => this.setState({ isLoading: false })
render = () => (
<WrappedComponent
doneLoading={this.doneLoading}
isLoading={this.state.isLoading}
{...this.props}
/>
);
}
return withRouter(Wrapper);
};
孩子(可以从孩子的this.props
内部访问传递的HOC方法/状态):
export default class Child extends PureComponent {
componentDidMount = () => {
fetch("someURL")
.then(response => response.json())
.then(json => this.setState({ list: json }), () => this.props.doneLoading());
};
render = () =>
this.props.isLoading
? <Spinner />
: <DisplayList list={...this.state.list} />
}
缺点是每个子组件都需要导入Spinner
并检查isLoading
是否为假。
为了使它在高度嵌套的组件之间工作,您很有可能希望/需要集成Redux。此外,您需要让已安装的容器在每次更改路线时调度一个操作来更新/重置isLoading
Redux状态。无论哪种方式,如果您想变干,它都不是一个简单而优雅的解决方案。
工作示例(此示例只是通过超时设置/取消了HOC状态):https://codesandbox.io/s/2zo8lj44pr
Wrapper.js
import React, { Component, Fragment } from "react";
import { withRouter } from "react-router";
import Header from "./Header";
import Spinner from "./Spinner";
export default WrappedComponent => {
class Wrapper extends Component {
state = { isLoading: true };
componentDidMount = () => this.setTimer();
componentDidUpdate = prevProps => {
if (this.props.location !== prevProps.location) {
this.clearTimer();
this.setState({ isLoading: true }, () => this.setTimer());
}
};
clearTimer = () => clearTimeout(this.timeout);
timer = () => this.setState({ isLoading: false }, () => this.clearTimer());
setTimer = () => (this.timeout = setTimeout(this.timer, 3000));
render = () => (
<Fragment>
<Header />
{this.state.isLoading
? <Spinner />
: <WrappedComponent {...this.props} />
</Fragment>
);
}
return withRouter(Wrapper);
};
index.js
import React from "react";
import { render } from "react-dom";
import { BrowserRouter, Switch, Route } from "react-router-dom";
import Home from "../components/Home";
import Schedule from "../components/Schedule";
import Wrapper from "./components/Wrapper";
render(
<BrowserRouter>
<Switch>
<Route exact path="/" component={Wrapper(Home)} />
<Route path="/schedule" component={Wrapper(Schedule)} />
</Switch>
</BrowserRouter>,
document.getElementById("root")
);
答案 1 :(得分:0)
我相信react-loadable可以帮助您实现这一目标,也可以从code splitting中受益。
答案 2 :(得分:0)
我的尝试:
return <Switch>
<Route
exact
path={loading ? '*' : '/'}
component={LoadingRoute} />
<Route
path={loginPaths}
component={LoginLayout}
/>
<Route
path={adminPaths}
component={AdminLayout}
/>
<Route component={NotFound} />
</Switch>
在这种情况下,loginPaths
和adminPaths
都没有路径/
,因此默认的加载路径是/
。如果根路径很重要,则可以使用;
路径,因此它不会与任何内容匹配。我正在使用react-router-transition中的AnimatedSwitch
,因此过渡之间的状态很重要。有了这个,您的App会说何时加载。