Javascript 当用户手动而不是通过链接输入URL时,如何处理?

Javascript 当用户手动而不是通过链接输入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

我有一个组件(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;
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();
}