在功能组件中使用位置状态



我正在做一个React项目,该项目要求应用程序URL是完全声明的、静态的和不可变的,所以:

https://exampleurl.com/path/to/app/index.html

但没有以下内容:

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

因此,该项目使用statewithRouter来提供基本的应用程序导航。负责的组成部分如下:

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);

location.state对象由<Link />组件设置:

<Link to={{ state: {activeDisplay: 'start'} }}>
<button type="button">Home</button>
</Link>

结果是在URL保持不变的情况下,在整个应用程序中进行正常的浏览器导航。

我的问题是:如何将上面基于类的RenderDisplay组件转换为功能组件(使用钩子(?

我已经尝试了useEffectuseStateuseLocation的几种排列,但我显然不太了解钩子,无法重现上面基于类的组件的行为。

所以,我们总是需要做的一些步骤:

  1. 不需要HOCs,特别是withRouter。我们可以使用useHistory挂钩
  2. 构造函数或componentDidMount的所有初始化都可以直接在状态中完成,也可以在只运行一次的useEffect(空依赖数组(中完成
  3. 所有对状态的更新,特别是来自componentDidUpdate的更新,都可以在useEffect中完成,这取决于您的状态变量。在您的特定情况下,您还需要以前的prop。在这种情况下,我们可以创建一个自定义钩子并使用它。在我的情况下,它将是usePrev
  4. 所有清理任务,特别是来自componentWillUnmount的清理任务,都可以包含在返回清理操作的useEffect

记住这些事情,这些可能是需要做的更改:

注意:在此过程中,我意识到您正在尝试渲染数组。我修改了它以渲染单个元素,否则您可以更新它。

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;

你能试试这个吗?您可以通过这种方式将类组件转换为函数。如果这有帮助,请告诉我。

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;

也适用于您的这段代码,

componentDidUpdate(prevProps, prevState) {
if (this.props.location !== prevProps.location) {
this.setState(this.props.location.state);
}
}

我们需要处理另一个useEffect钩子。

相关内容

  • 没有找到相关文章

最新更新