[英]Using Location State in Functional Component
I'm working on a React project that requires the app URL to be fully-declared, static and immutable, so just:我正在开发一个 React 项目,该项目要求应用 URL 是完全声明的、静态的和不可变的,所以只需:
https://exampleurl.com/path/to/app/index.html
..but none of the following: ..但以下都不是:
https://exampleurl.com/path/to/app/
https://exampleurl.com/path/to/app/index.html?query=value
https://exampleurl.com/path/to/app/subdir/index.html
So, the project uses state
and withRouter
to provide basic app navigation.因此,该项目使用
state
和withRouter
来提供基本的应用导航。 The responsible component is as follows:负责的组件如下:
import React from 'react';
import { withRouter} from "react-router-dom";
import RenderNav from './RenderNav';
import Cohort from '../view/Cohort';
import Holdings from '../view/Holdings';
import Policy from '../view/Policy';
import Search from '../view/Search';
import Start from '../view/Start';
import Training from '../view/Training';
import WatchList from '../view/WatchList';
class RenderDisplay extends React.Component {
constructor(props) {
super(props);
this.state = this.props.location.state || { activeDisplay: 'start' };
this.props.history.replace(this.props.location.pathname, this.state);
}
componentDidUpdate(prevProps, prevState) {
if (this.props.location !== prevProps.location) {
this.setState(this.props.location.state);
}
}
setDisplay() {
let displayMode = [];
let d = this.state.activeDisplay;
switch(d) {
case 'start': displayMode = [
<Start key={`display-${d}`} />
]; break;
// ...and so on - activeDisplay determines displayMode (and so screen contents)
default: displayMode = [<div>Error</div>]; break;
}; return displayMode;
}
render() {
return (
<div className="container">
{this.setDisplay()}
</div>
);
}
}
export default withRouter(RenderDisplay);
The location.state
object is set by the <Link />
component: location.state
对象由<Link />
组件设置:
<Link to={{ state: {activeDisplay: 'start'} }}>
<button type="button">Home</button>
</Link>
The result is normal browser navigation throughout the app while the URL remains unchanged.结果是整个应用程序的浏览器导航正常,而 URL 保持不变。
My question is: how can the class-based RenderDisplay
component above be converted to a functional component (using hooks)?我的问题是:如何将上面基于类的
RenderDisplay
组件转换为功能组件(使用钩子)?
I've tried several permutations of useEffect
, useState
, and useLocation
, but I clearly don't understand hooks well enough to reproduce the behavior of the class-based component above.我已经尝试了
useEffect
、 useState
和useLocation
几种排列,但我显然对钩子的理解不够好,无法重现上面基于类的组件的行为。
So,some steps that we always need to do:所以,我们总是需要做的一些步骤:
withRouter
.withRouter
,特别是withRouter
。 We can use the useHistory
hook instead.useHistory
钩子。componentDidMount
can be done either directly in state, or in an useEffect
that only runs once (empty dependency array).componentDidMount
初始化都可以直接在 state 中完成,也可以在只运行一次的useEffect
中完成(空依赖数组)。componentDidUpdate
can be done in an useEffect
that depends on your state variable.componentDidUpdate
更新都可以在依赖于您的状态变量的useEffect
中完成。 In your specific case, you need the previous prop
as well.prop
。 In these situations, we can create a custom hook and use it.usePrev
.usePrev
。componentWillUnmount
can be covered in an useEffect
that returns the cleanup action.componentWillUnmount
清理任务都可以包含在返回清理操作的useEffect
中。 Keeping these things in mind, these are probably the changes that need to be done:记住这些事情,这些可能是需要做的改变:
Note: During this, I realized you are trying to render an array.注意:在此期间,我意识到您正在尝试渲染一个数组。 I modified it to render a single element, you can update it otherwise.
我修改它以呈现单个元素,否则您可以更新它。
import {useRef} from "react";
export const usePrev = (value) => {
const ref = useRef();
useEffect(() => {
ref.current = value;
}, [value]);
return ref.current;
}
import React, {useState, useEffect} from 'react';
import {useHistory, useLocation} from 'react-router-dom';
import RenderNav from './RenderNav';
import Cohort from '../view/Cohort';
import Holdings from '../view/Holdings';
import Policy from '../view/Policy';
import Search from '../view/Search';
import Start from '../view/Start';
import Training from '../view/Training';
import WatchList from '../view/WatchList';
import usePrev from './usePrev';
const RenderDisplay = (props) => {
const history = useHistory();
const location = useLocation();
const prevLocation = usePrev(location);
const [componentState, setComponentState] = useState(location.state || { activeDisplay: 'start' });
useEffect(() => {
history.replace(location.pathname, componentState);
}, [location.pathname, history]);
useEffect(() => {
if (location.state.activeDisplay !== prevLocation.state.activeDisplay) {
setComponentState(location.state);
}
}, [location]);
setDisplay() {
let displayMode;
let d = componentState.activeDisplay;
switch(d) {
case 'start': displayMode = <Start key={`display-${d}`} />;
break;
// ...and so on - activeDisplay determines displayMode (and so screen contents)
default: displayMode = <div>Error</div>; break;
};
return displayMode;
}
return (
<div className="container">
{setDisplay()}
</div>
);
}
export default RenderDisplay;
Can you try this?你能试试这个吗? You can convert your class component to function this way.
您可以将类组件转换为这种方式。 Let me know if this helps.
如果这有帮助,请告诉我。
import { useEffect, useState } from "react";
import { useHistory, useLocation } from "react-router-dom";
function RenderDisplay() {
const location = useLocation();
const history = useHistory();
const [state, setState] = useState(
location.state || { activeDisplay: "start" }
);
useEffect(() => {
history.replace(location.pathname, state);
}, [history, location, state]);
const setDisplay = () => {
let displayMode = [];
const d = state.activeDisplay;
switch (d) {
case "start":
displayMode = [<Start key={`display-${d}`} />];
break;
// ...and so on - activeDisplay determines displayMode (and so screen contents)
default:
displayMode = [<div>Error</div>];
break;
}
return displayMode;
};
return <div className="container">{setDisplay()}</div>;
}
export default RenderDisplay;
Also for your this block of code,同样对于您的这段代码,
componentDidUpdate(prevProps, prevState) {
if (this.props.location !== prevProps.location) {
this.setState(this.props.location.state);
}
}
We need to handle in another useEffect
hook.我们需要在另一个
useEffect
钩子中处理。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.