React Router v6 更改 URL 但不呈现

戈蒂27

我正在使用 React Router V6 开发 Web 应用程序。每个用户都有几个项目,根据 React Router 文档,我以这种方式声明路由:

<Routes>
    <Route index path='/' element={<GeneralOverview user={props.user}> </GeneralOverview>}/>
    ... 
    <Route path='/users/:userId' element={<UserPage></UserPage>} />
    <Route path='/create-project' element={<CreateProject></CreateProject>} />
    <Route path='/projects/*'>
        <Route path=':projectId' element={<ProjectOverview />} />
    <Route path=':projectId/repos' element={<ProjectRepos></ProjectRepos>} />
    <Route path=':projectId/issues' element={<ProjectIssues></ProjectIssues>}/>
    <Route path=':projectId/issues/:issueId' element={<IssuePage></IssuePage>}></Route>
    ... 
</Routes>

我构建了一个侧边栏,它显示了所有用户项目的列表,其中包含可导航到项目页面的可点击元素。这是侧边栏组件的子组件,它呈现项目列表:

let ProjectsList = props => {
    let navigate = useNavigate();
    return props.projects.map(project =>
    <CNavItem key={project._id} href='#' onClick={event => {
        event.preventDefault();
        navigate("/projects/" + project._id);
    }}>
        {project.name}
    </CNavItem>)
}

单击该项目,URL 会从/projects/<old-id>变为/projects/<new-id>(正确),但该组件仍显示有关上一个项目的信息。

我已经尝试了几种修复方法,例如 using navigate("/projects/" + project._id, {replace: true}); ,但没有任何效果。唯一的方法似乎是使用 href,但我希望这个项目是一个单页网络应用程序。所以我只需要导航而不重新加载整个文档。

--- 编辑:ProjectOverview 组件代码 ---

根据要求,这里是项目概述代码,省略了一些“无用”部分。

import React, { useState, useEffect } from 'react';
import axios from 'axios';
import { Link, Navigate, useLocation, useNavigate, useParams } from "react-router-dom";
import { CContainer, CAlert, CCard, CRow, CCol, CHeader, CHeaderBrand,
    CCardBody, CCardHeader, CCardTitle, CButton, CModal, CModalHeader, 
    CModalTitle, CModalBody, CFormInput, CModalFooter, CCardText, CFormLabel, 
    CFormSelect, CBadge, CHeaderDivider, CDropdownDivider} from '@coreui/react';
import CIcon from '@coreui/icons-react';
import * as icon from '@coreui/icons';
import { CChart } from '@coreui/react-chartjs';


const ProjectOverview = props => {
    let { projectId } = useParams();
    let navigate = useNavigate();
    
    let [project, setProject] = useState();
    let [owner, setOwner] = useState();
    let [repos, setRepos] = useState();

    /**
     * some state variables for errors, handlers and data distribution
     */

    useEffect(() => {
        axios.get('http://localhost:4000/projects/' + projectId, {withCredentials:true}).then(res => {
            setProject(res.data);
            axios.get('http://localhost:4000/projects/' + projectId + '/owner', {withCredentials:true}).then(res => {
                setOwner(res.data);
                axios.get('http://localhost:4000/projects/' + projectId + '/repos', {withCredentials:true}).then(res => {
                    setRepos(res.data);
                    axios.get('http://localhost:4000/projects/' + projectId + '/issues', {withCredentials:true}).then(res => {
                        /**
                         * distributing data for charts
                         */
                        let repoDistrubution = [0,0,0,0];
                        let csetDistribution = [0,0,0,0];
                        let cSum = 0, rSum = 0;
                        for (const issue of res.data) {
                            if (issue.repoId) {
                                switch (issue.status) {
                                    case 'open': repoDistrubution[0]++; break;
                                    case 'ignored': repoDistrubution[1]++; break;
                                    case 'working on': repoDistrubution[2]++; break;
                                    case 'fixed': repoDistrubution[3]++; break;
                                }
                                rSum++;
                            } else {
                                switch (issue.status) {
                                    case 'open': csetDistribution[0]++; break;
                                    case 'ignored': csetDistribution[1]++; break;
                                    case 'working on': csetDistribution[2]++; break;
                                    case 'fixed': csetDistribution[3]++; break;
                                }
                                cSum++;
                            }
                        }
                        setCsetIssueDistribution(csetDistribution);
                        setReposIssueDistribution(repoDistrubution);
                        setCsetSum(cSum); setReposSum(rSum);
                    })
                });
            });
        }).catch(err => {
            if (err.status === 404) {
                setProjectNotFound(true);
            }
            console.log(err)
        });
        axios.get('https://api.github.com/user/repos', {headers: {
            'Authorization': 'Bearer ' + localStorage.getItem('github_token')
        }, params: {'per_page': 100, 'page':1}}
        ).then(res => {
            let repos = ['select one of your repos'];
            for (const repo of res.data) {
                repos.push(repo.full_name)
            }
            setAvailableRepos(repos);
        }).catch(err => console.log(err));
        axios.get('http://localhost:4000/avaiable-assessment', {withCredentials: true}).then(res => {
            let assessments = []
            for (const assessment of res.data) {
                assessments.push({
                    id: assessment.Id,
                    name: assessment.Assessment_Name
                })
            }
            setAvaiableAssessments(assessments);
        })
    }, []);

    /**
     * some handlers
     */

    return <CContainer>

        {project && repos ? (
            <div>
                <CHeader className="" style={{paddingTop:"0rem"}}>
                    <CCol>
                        <CRow>
                        <CCol md='auto' style={{borderRight: '1px solid grey'}}>   
                        <CHeaderBrand >Project name: {project.name}</CHeaderBrand>
                        </CCol>
                        <CCol md='auto' style={{borderRight: '1px solid grey', marginLeft:'1rem'}}>
                        <CHeaderBrand>Owner: {owner && owner.username}</CHeaderBrand>
                        </CCol>
                        <CCol md='auto' style={{marginLeft:'1rem'}}>
                        <CHeaderBrand>Status: {project.status}</CHeaderBrand>
                        </CCol>
                        </CRow>
                    </CCol>
                    <CCol md='auto' style={{margileft:'1rem', marginRight:'1rem'}}>
                        // buttons and handlers
                    </CCol>
                </CHeader><br/>
                <CRow>
                    <CCol>
                        <CCard>
                            <CCardBody>
                                <CCardTitle>Details</CCardTitle>
                                <CCardText>
                                    Description: {project.description}
                                </CCardText>
                                <CCardText>
                                    <CBadge style={{marginRight:'1rem'}} className="bg-dark">{project.issues.length}</CBadge> 
                                    <Link to={'/projects/' + project._id + '/issues'}
                                        state={{project: project}}
                                        style={{ textDecoration: 'none'}}>
                                        Issues
                                    </Link>
                                </CCardText>
                            </CCardBody>
                        </CCard>
                    </CCol>
                    <CCol>
                        <CCard>
                            <CCardBody>
                                <CCardTitle>
                                    Repositories
                                    <CButton onClick={() => setAddingRepo(true)}>
                                        <CIcon icon={icon.cilPlus}></CIcon> 
                                    </CButton> 
                                </CCardTitle>
                                <RepoList setProject={setProject} project={project} repos={repos}></RepoList>
                                // just prints the list of repos and handles thier removal
                            </CCardBody>
                        </CCard>
                    </CCol>
                    <CCol>
                        <CCard>
                            <CCardBody>
                                <CCardTitle>
                                    Collaborators
                                    <CButton onClick={() => setAddingCollab(true)}>
                                        <CIcon icon={icon.cilPlus}></CIcon> 
                                    </CButton> 
                                </CCardTitle>
                                <CollaboratorsList setProject={setProject} project={project} ></CollaboratorsList>
                                // just prints the list of collaborators and handles thier removal
                            </CCardBody>
                        </CCard>
                    </CCol>
                </CRow>
            </div>
        ) : (
            <div> skeleton (TODO)</div>
        ) }
    </CContainer>
}

export default ProjectOverview;
德鲁里斯

ProjectOverview组件被渲染并且路由路径发生projectId变化时,useEffect不会再次触发钩子以获取任何数据。

添加projectIduseEffect钩子的依赖数组中,以便在projectId值更改时再次运行效果。

const ProjectOverview = (props) => {
  const { projectId } = useParams();
  ...

  useEffect(() => {
    axios
      .get("http://localhost:4000/projects/" + projectId, {
        withCredentials: true
      })
      .then((res) => {
        setProject(res.data);
        axios
          .get("http://localhost:4000/projects/" + projectId + "/owner", {
            withCredentials: true
          })
          .then((res) => {
            setOwner(res.data);
            axios
              .get("http://localhost:4000/projects/" + projectId + "/repos", {
                withCredentials: true
              })
              .then((res) => {
                setRepos(res.data);
                axios
                  .get(
                    "http://localhost:4000/projects/" + projectId + "/issues",
                    { withCredentials: true }
                  )
                  .then((res) => {
                    ...
                  });
              });
          });
      })
      .catch((err) => {
        ...
      });
    ...
  }, [projectId]);

此外,作为一个建议,你应该扁平化你的 Promise 链。创建 Promise 链是为了解决一个称为“嵌套地狱”的问题,其中涉及嵌套异步回调,并且您还没有逃脱嵌套问题。

例子:

const options = { withCredentials: true };
axios
  .get("http://localhost:4000/projects/" + projectId, options)
  .then((res) => {
    setProject(res.data);
    return axios.get(
      "http://localhost:4000/projects/" + projectId + "/owner",
      options
    );
  })
  .then((res) => {
    setOwner(res.data);
    return axios.get(
      "http://localhost:4000/projects/" + projectId + "/repos",
      options
    );
  })
  .then((res) => {
    setRepos(res.data);
    return axios.get(
      "http://localhost:4000/projects/" + projectId + "/issues",
      options
    );
  })
  .then((res) => {
    /**
     * distributing data for charts
     */
    const repoDistrubution = [0, 0, 0, 0];
    const csetDistribution = [0, 0, 0, 0];
    let cSum = 0;
    let rSum = 0;
    for (const issue of res.data) {
      ...
    }
    setCsetIssueDistribution(csetDistribution);
    setReposIssueDistribution(repoDistrubution);
    setCsetSum(cSum);
    setReposSum(rSum);
  })
  .catch((err) => {
    if (err.status === 404) {
      setProjectNotFound(true);
    }
    console.log(err);
  });

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

React-router-dom v6,URL更改但组件未呈现

React Router v6 Link 组件不会更改根 url 的页面

React-router链接更改了URL,但不重新呈现

React Router Link 更改 URL 但不呈现组件 - Rest Country API

React Router Dom - React Router 更改 url 但不更改页面

URL 更改但组件未呈现 - React Router

React Router 更改 URL 但不渲染组件

为什么React Router更改URL但不更改视图

使用 react.js 和 react router v6 根据当前 URL 执行条件

React-Router V4,URL更改但组件未呈现

React-Router:组件未呈现但 URL 更改

URL更改而无需在React Router中重新呈现

即使链接 URL 更改,React Router 也不会重新呈现

React Router v6 onclick

React Router V6 activeStyle 问题

查看不会更新,但URL在React Router V6中会显示

react-router v6:使用 searchParams 导航到 URL

React Router 的多个参数更改 url 但不是组件

React-router-dom V6 没有正确更改路由(刷新 - 需要 f5 页面)

React Router 更改了 URL 地址,但它呈现了另一个组件 - Material ui V. 5.0

React-Router-Dom 的低级路由器仅导航到新 URL,但不呈现组件

如何在 React Router v6 中重定向?

React Router Dom v6 中的重定向

React Router v6 `useRouter` Hook with `basename` 和 Redirection

React Router Dom V6 嵌套路由属性

react-router v6 双渲染组件

使用React Router V6实施受保护的路由

React-Router (experimental v6) 渲染问题?

React Navigation Router V6无效的挂钩调用