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.jsJavascript 当用户手动而不是通过链接输入URL时,如何处理?,javascript,reactjs,react-router,Javascript,Reactjs,React Router,我有一个组件(ContainerMain.js),它从API获取容器列表,然后在按钮中呈现每个容器名称。单击其中一个按钮时,状态将通过“history.push(/ContainerContents/${id},{container:container})”传递给另一个组件(ContainerContents.js)。 当我在ContainerMain.js中选择一个按钮时,它就会工作 在刷新和输入url时处理(“http://localhost:3000/containercontents/6
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;
import React,{useState,useffect}来自“React”
从“react router dom”导入{Link,Route,useHistory}
从“/ContainerContent”导入ContainerContent;
const ContainerMain=(道具)=>{
const[containers,setContainers]=useState([]);
//const[showContainerContents,setShowContainerContents]=useState(false);
//const[selectedContainerId,setSelectedContainerId]=useState();
const history=useHistory();
const getContainers=async()=>{
const url=“/api/containers”;
等待获取(url)
.then(response=>response.json())
.然后(响应=>setContainers(响应))
.catch(()=>console.log(“无法访问“+url+”响应。被浏览器阻止了?”)
}
const deleteContainer=async(containerId)=>{
让result=window.confirm(“您确定要删除“+容器.find(container=>container.id==containerId).name+”?”;
如果(结果){
setContainers(containers.filter(container=>container.id!==containerId))
fetch(`api/containers/${containerId}`{
方法:“删除”,
})
.then(res=>res.json())//或res.json()
.then(res=>console.log(res))
}
否则{
返回
}
}
//const onButtonClick=(集装箱ID)=>{
//设置ShowContainerContent(真)
//设置选定的containerId(containerId)
// }
useffect(()=>{
getContainers();
}, []);
返回(
我的食物容器
{containers.map(container=>(
-
deleteContainer(container.id)}className=“按钮四舍五入即危险”>删除
history.push(`/containercontents/${container.id}`,{container:container})}className=“按钮为主”>{container.name}
{/* */}
{/*{container.name}*/}
{/*{container.name}
*/}
))}
{/*{showContainerContents?:null}*/}
);
}
导出默认容器名;
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;
import React,{useffect,useState}来自“React”;
常量容器内容=(道具)=>{
const[container,setContainer]=useState({});
useffect(()=>{
const fetchContainer=async()=>{
const{id}=props.match.params;
log(“这是id:+id”)
让url=`/api/containers/${id}`;
等待获取(url)
.then(response=>response.json())
.然后(响应=>setContainer(响应))
.catch(()=>console.log(“无法访问“+url+”响应。被浏览器阻止了?”)
}
fetchContainer();
},[props.match.params]);
返回(
{/*在刷新并按预期输入url时将不起作用*/}
{props.location.state.container.name}
{container.name}
)
}
导出默认容器内容;
据我所知,您希望能够在使用该方法时从按钮单击中获取id,而在手动访问url时从url中获取id
一种简单的方法是,如果props.match.params不存在,只需从url检索id即可?您应该能够使用useLocation钩子访问它,然后我相信有一种更简单的方法,但是您可以只解析您想要的id
比如:
我还相信,如果您感兴趣,react router dom现在支持一种更简单的方法来访问参数
我不知道如何仅使用一个数据源,这取决于数据是来自url还是按钮
这确实是使用Redux或其他一些状态管理系统背后的全部想法——为整个应用程序提供一个通用的真相存储库,以便您始终知道数据来自何处。所以,是的,最终最好是实现这样的东西,在必须处理巨大的反应状态和支撑钻井之后,您可能会想这样做,但无论如何这都不是必要的
只要您的容器
数据在组件树中的位置足够高,所有需要它访问它的组件都可以通过道具将它传递给它们。容器将永远只存在一个地方,因此您可以确定,如果它不在那里,则需要将其取出。从您所有的注释代码来看,ContainerMain
是否应该呈现ContainerContents
,这有点不清楚,但可以说它没有。这里是组件结构的简化版本——其基本思想是在请求之前检查数据属性是否存在
const location = useLocation();
let url_segs = location.pathname.split("/");
let id = url_segs[url_segs.length - 1]
export default function App() {
const [containers, setContainers] = useState([]);
return (
<Router>
<Switch>
<Route exact path="/">
<ContainerMain
containers={containers}
setContainers={setContainers}
/>
</Route>
<Route exact path="/containercontents/:id">
<ContainerContents
containers={containers}
setContainers={setContainers}
/>
</Route>
</Switch>
</Router>
);
}
function ContainerMain({ containers, setContainers }) {
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?")
);
};
useEffect(() => {
getContainers();
}, [getContainers]);
return (
<div>
<strong>MY FOOD CONTAINERS</strong>
<br />
<br />
<ul>
{containers.map(container => (
<li key={container.id}>
<div>
<button
onClick={() =>
history.push(`/containercontents/${container.id}`)
}
className="button is-primary"
>
{container.name}
</button>
</div>
</li>
))}
</ul>
</div>
);
}
function ContainerContents({ containers, setContainers }) {
const match = useRouteMatch();
useEffect(() => {
const fetchContainer = async id => {
let url = `/api/containers/${id}`;
await fetch(url)
.then(response => response.json())
.then(response => {
setContainers([...containers, response]);
})
.catch(() =>
console.log("Can’t access " + url + " response. Blocked by browser?")
);
};
const found = containers.find(el => el.id === match.params.id);
if (!found) {
fetchContainer(match.params.id);
}
}, [match.params, containers, setContainers]);
function selectContainer() {
const found = containers.find(el => el.id === match.params.id);
return found ? (
<div>
<h1>{found.name}</h1>
</div>
) : null;
}
return selectContainer();
}