javascript - 当用户手动输入URL而不是通过链接时如何处理?
问题描述
我有一个组件(ContainerMain.js),它从 API 获取容器列表,随后在按钮中呈现每个容器名称。单击其中一个按钮时,状态将使用“history.push(/containercontents/${id}, {container: container})”传递给另一个组件(ContainerContents.js)。当我在 ContainerMain.js 中选择一个按钮时,它会起作用。
为了处理当我手动刷新并输入 url ("http://localhost:3000/containercontents/6") 导致 ContainerContents.js 被渲染时,我使用 "props.match.params.id" 来获取 id容器,然后从那里去。
这是据我所知,因为我不知道如何仅使用一种数据源,具体取决于该数据是来自 url 还是来自按钮。那有意义吗?即使我这样做了,这个解决方案似乎也很糟糕,我觉得我错过了一种处理这种情况的明显方法。我对 Redux/Context 不是很熟悉,但我相信我可以使用其中之一来解决这个问题。我想知道在使用 Redux/Context 之前是否有一种更简单、更常见的方法来处理这种情况,假设我可以使用它们来处理这种情况。
ContainerMain.js
import React, { useState, useEffect } from 'react'
import { Link, Route, useHistory } from 'react-router-dom'
import ContainerContents from './ContainerContents';
const ContainerMain = (props) => {
const [containers, setContainers] = useState([]);
// const [showContainerContents, setShowContainerContents] = useState(false);
// const [selectedContainerId, setSelectedContainerId] = useState();
const history = useHistory();
const getContainers = async () => {
const url = "/api/containers";
await fetch(url)
.then(response => response.json())
.then(response => setContainers(response))
.catch(() => console.log("Can’t access " + url + " response. Blocked by browser?"))
}
const deleteContainer = async (containerId) => {
let result = window.confirm("Are you sure you want to delete your " + containers.find(container => container.id === containerId).name + "?");
if (result) {
setContainers(containers.filter(container => container.id !== containerId))
fetch(`api/containers/${containerId}`, {
method: 'DELETE',
})
.then(res => res.json()) // or res.json()
.then(res => console.log(res))
}
else {
return
}
}
// const onButtonClick = (containerId) => {
// setShowContainerContents(true)
// setSelectedContainerId(containerId)
// }
useEffect(() => {
getContainers();
}, []);
return (
<div>
<strong>MY FOOD CONTAINERS</strong>
<br></br><br></br>
<ul>
{containers.map(container => (
<li key={container.id}>
<div>
<button onClick={() => deleteContainer(container.id)} className="button is-rounded is-danger">Delete</button>
<button onClick={() => history.push(`/containercontents/${container.id}`, {container: container})} className="button is-primary">{container.name}</button>
{/* <Route
path="/ContainerContents" component={HomePage}/> */}
{/* <Link to={`/containercontents/${container.id}`}>{container.name}</Link> */}
{/* <Link to={{
pathname: `/containercontents/${container.name}`,
state: {container: container}
}}>{container.name}
</Link> */}
</div>
</li>
))}
</ul>
{/* {showContainerContents ? <ContainerContents containerId={selectedContainerId} /> : null} */}
</div>
);
}
export default ContainerMain;
ContainerContents.js
import React, { useEffect, useState} from 'react';
const ContainerContents = (props) => {
const [container, setContainer] = useState({});
useEffect(() => {
const fetchContainer = async () => {
const { id } = props.match.params;
console.log("This is the id: " + id)
let url = `/api/containers/${id}`;
await fetch(url)
.then(response => response.json())
.then(response => setContainer(response))
.catch(() => console.log("Can’t access " + url + " response. Blocked by browser?"))
}
fetchContainer();
}, [props.match.params]);
return (
<div>
{/* will not work when I refresh and enter url as expected*/}
<h1>{props.location.state.container.name}</h1>
<h1>{container.name}</h1>
</div>
)
}
export default ContainerContents;
解决方案
据我了解,您希望能够在使用该方法时从按钮单击中获取 id,并在手动到达时从 url 中获取 id。
一个简单的方法可能是在 props.match.params 不存在的情况下从 url 中检索 id?您应该能够使用 useLocation 挂钩来访问它,然后我确定有一种更简单的方法,但您可以只解析您想要的 id。
像:
const location = useLocation();
let url_segs = location.pathname.split("/");
let id = url_segs[url_segs.length - 1]
另外我相信 react-router-dom 现在支持useParams如果您有兴趣,可以使用更简单的方法来访问参数。