有一个目录组件,一些redux存储;react 上下文提供程序代码.在路由v6之前,他们包装了一个包含目录子路由的嵌套<BrowserRouter>,如下所示

之前

client/src/components/Catalogue/index.js

import React, { useCallback, useEffect, useState }  from 'react';
import { BrowserRouter as Router, Route } from "react-router-dom";
import { Provider, connect } from "react-redux";
import { createStore, combineReducers } from "redux";

import { getPeopleBy, getChaptersBy, getPostsBy } from "../../api"
import playlistReducer from "../../store/reducers/playlists";

import SideBar from "../CatalogueSidebar/SideBar";
import CatalogueHeader from "../CatalogueHeader/CatalogueHeader"

import CatalogueHome from "../CatalogueHome/CatalogueHome";
import CatalogueSearch from "../CatalogueSearch";
import People from "../People/People";
import Chapters from "../Chapters/Chapters";
import Posts from "../Posts/Posts";
import PostDetail from "../PostDetail/PostDetail";

import FooterBar from "../FooterBar/FooterBar";
import style from "./Catalogue.module.css"

const Catalogue = () => {

  const [chapters, setChapters] = useState(null)
  const [people, setPeople] = useState(null)
  const [posts, setPosts] = useState(null)

  const fetchCatalogue = async () => {
    let chapters = await getChaptersBy("latest")
    let people = await getPeopleBy("active")
    let posts = await getPostsBy("recently_added")

    return { chapters, people, posts }
  }

  useEffect(() => {
      document.documentElement.className = ""; //<head>
      document.body.className = style.CatalogueBody; //<body>

      fetchCatalogue().then(response => {

        setChapters(response.chapters)
        setPeople(response.people)
        setPosts(response.posts)
      })
      return () => {
        setChapters(null)
        setPeople(null)
        setPosts(null)
      }
  }, [])

  const reducers = combineReducers({
      chapters: playlistReducer,
      people: playlistReducer,
  });
  
  const store = createStore(reducers);

  return (
    <Provider store={store}>
      <div className={style.App}>
        <Router>
          <SideBar />
          <CatalogueHeader account={{display_name: "User"}}/>
          <Route path="/catalogue" exact>
            <CatalogueHome chapters={chapters} people={people} posts={posts}/>
          </Route>   
          <Route path="/catalogue/search">
            <CatalogueSearch />
          </Route>
          <Route path="/catalogue/posts">
            <Posts/>
          </Route>   
          <Route path="/catalogue/posts/:id">
            <PostDetail />
          </Route>
          <Route path="/catalogue/people">
            <People />
          </Route> 
          <Route path="/catalogue/chapters">
            <Chapters />
          </Route> 
        </Router>
        <FooterBar />
      </div>
    </Provider>
  );
};

const mapStateToProps = (state) => {
  return {
    posts: state.posts,
    people: state.people,
  };
};

const mapDispatchToProps = (dispatch) => {
  return {
    initPosts: (data) => dispatch({ type: "init", posts: data }),
    initPeople: (data) => dispatch({ type: "init", people: data }),
  };
};

export default Catalogue;

client/src/components/App.js

import React, { useState } from "react";
import { Route, Switch, BrowserRouter } from "react-router-dom";
import TierA from "./TierA"
import TierB from "./TierB"
import Catalogue from "./Catalogue"
import Admin from "./Admin"
import NotFound from "./NotFound"

import PlayerContext from "./Player/context"
import SearchContext from "./Search/context"
import CatalogueSearchContext from "./CatalogueSearch/context"
import { useSearch } from "../hooks/useSearch"

const App = () => {

    const searchText = useSearch()
    const [playerItem, setPlayerItem] = useState(null)

    return (
        <React.Fragment>
        <SearchContext.Provider value={searchText}>
        <CatalogueSearchContext.Provider value={searchText}>
        <PlayerContext.Provider value={{ playerItem, setPlayerItem }}>
            <BrowserRouter basename={process.env.PUBLIC_URL}>
                <Switch>
                    <Route component={TierA} exact path="/tier_a" />
                    <Route component={TierB} exact path="/tier_b" />
                    <Route component={Catalogue} path="/catalogue" />
                    <Route component={Admin} path="/admin" />
                    <Route component={NotFound} />
                </Switch>
            </BrowserRouter>
        </PlayerContext.Provider>
        </CatalogueSearchContext.Provider>
        </SearchContext.Provider>
        </React.Fragment>
    )
}


export default Routes;

之后

更新"react-router-dom": "^5.1.2""react-router-dom": "^6.3.0",目录路由有一些问题.将Catalogue个子组件移动到App,但仅保留CatalogueHome个,将为目录索引"/"呈现

client/src/components/Catalogue/index.js

 import React, { useCallback, useEffect, useState }  from 'react';
import { BrowserRouter as Router, Route, Routes } from "react-router-dom";
import { Provider, connect } from "react-redux";
import { createStore, combineReducers } from "redux";

import { getPeopleBy, getChaptersBy, getPostsBy } from "../../api"
import playlistReducer from "../../store/reducers/playlists";
import playingReducer from "../../store/reducers/playing";

import SideBar from "../CatalogueSidebar/SideBar";
import CatalogueHeader from "../CatalogueHeader/CatalogueHeader"

import CatalogueHome from "../CatalogueHome/CatalogueHome";
import CatalogueSearch from "../CatalogueSearch";
import Posts from "../Posts/Posts";
import PostDetail from "../PostDetail/PostDetail";
import People from "../People/People";
import Chapters from "../Chapters/Chapters";

import FooterBar from "../FooterBar/FooterBar";
import style from "./Catalogue.module.css"

const Catalogue = () => {

  const [chapters, setChapters] = useState(null)
  const [people, setPeople] = useState(null)
  const [posts, setPosts] = useState(null)

  const fetchCatalogue = async () => {
    let chapters = await getChaptersBy("latest")
    let people = await getPeopleBy("active")
    let posts = await getPostsBy("recently_added")

    return { chapters, people, posts }
  }

  useEffect(() => {
      document.documentElement.className = ""; //<head>
      document.body.className = style.CatalogueBody; //<body>

      fetchCatalogue().then(response => {

        setChapters(response.chapters)
        setPeople(response.people)
        setPosts(response.posts)
      })
      return () => {
        setChapters(null)
        setPeople(null)
        setPosts(null)
      }
  }, [])

  const reducers = combineReducers({
      chapters: playlistReducer,
      people: playlistReducer,
  });
  
  const store = createStore(reducers);

  return (
    <Provider store={store}>
      <div className={style.App}>

          <SideBar />
          <CatalogueHeader account={{display_name: "User"}}/>

           <CatalogueHome chapters={chapters} people={people} posts={posts}/>

        <FooterBar />
      </div>
    </Provider>
  );
};

const mapStateToProps = (state) => {
  return {
    posts: state.posts,
    people: state.people,
  };
};

const mapDispatchToProps = (dispatch) => {
  return {
    initPosts: (data) => dispatch({ type: "init", posts: data }),
    initPeople: (data) => dispatch({ type: "init", people: data }),
  };
};

export default Catalogue;

新应用程序.js没有"catalogue"的绝对路径,因此它使用react router v6和<Outlet/>,但它缺少所有redux和;需要引用的上下文包装器:

import React, { useState } from "react";
import { BrowserRouter, Route, Routes, Outlet } from "react-router-dom";
import TierA from "./TierA"
import TierB from "./TierB"
import Catalogue from "./Catalogue"

import CatalogueHome from "./CatalogueHome/CatalogueHome";
import CatalogueSearch from "./CatalogueSearch";
import Chapters from "./Chapters/Chapters";
import PostDetail from "./PostDetail/PostDetail";
import People from "./People/People";
import Posts from "./Posts/Posts";

import Admin from "./Admin"
import NotFound from "./NotFound"

import PlayerContext from "./Player/context"
import SearchContext from "./Search/context"
import CatalogueSearchContext from "./CatalogueSearch/context"
import { useSearch } from "../hooks/useSearch"


const App = () => {

    const searchText = useSearch()
    const [playerItem, setPlayerItem] = useState(null)

    return (
        <React.Fragment>
        <SearchContext.Provider value={searchText}>
        <CatalogueSearchContext.Provider value={searchText}>
        <PlayerContext.Provider value={{ playerItem, setPlayerItem }}>
        <BrowserRouter basename={process.env.PUBLIC_URL}>
                <Routes>
                    <Route path="/tier_a" element={<TierA/>}/>
                    <Route path="/tier_b" element={<TierB/>}/>
                    <Route path="catalogue"> 
                        <Route index element={<Catalogue/>}/>
                        <Route path="search" element={<CatalogueSearch />}/>
                        <Route path="posts" element={<Post/>}/>  
                        <Route path="post/:id" element={<PostDetail />}/>
                        <Route path="people" element={<People />}/>
                        <Route path="chapters" element={<Chapters />}/>
                    </Route>
                    <Route path="/admin" element={<Admin/>}/>
                    <Route path="*" element={<NotFound/>}/>
                </Routes>
            </BrowserRouter>
        </PlayerContext.Provider>
        </CatalogueSearchContext.Provider>
        </SearchContext.Provider>
        </React.Fragment>
    )
}


export default App;

try 点击任何目录嵌套路由(如/catalogue/posts/catalogue/people)时,出现以下错误:

Uncaught Error: Could not find "store" in the context of "Connect(PostDetail)". Either wrap the root component in a <Provider>, or pass a custom React context provider to <Provider> and the corresponding React context consumer to Connect(PostDetail) in connect options.
    at ConnectFunction (connect.js:244:1)
    at renderWithHooks (react-dom.development.js:16175:1)
    at updateFunctionComponent (react-dom.development.js:20387:1)
    at updateSimpleMemoComponent (react-dom.development.js:20222:1)
    at updateMemoComponent (react-dom.development.js:20081:1)
    at beginWork (react-dom.development.js:22502:1)
    at HTMLUnknownElement.callCallback (react-dom.development.js:4161:1)
    at Object.invokeGuardedCallbackDev (react-dom.development.js:4210:1)
    at invokeGuardedCallback (react-dom.development.js:4274:1)
    at beginWork$1 (react-dom.development.js:27405:1)

我的问题是,我是否需要将Catalogue个代码(如useEffect()、states、contextProviders)移动到App.js才能让props 工作?"store"和;etc适用于每个目录子项.由于错误,我无法将提供程序代码放入<Routes> </Routes>

Error: [Provider] is not a <route> component. all component children of <routes> must be a <route> or <react.fragment>

请告知如何修复.提前感谢

推荐答案

问题是,目录组件是渲染Redux Provider的组件,而目录仅在路径为"/catalogue"作为索引路由时渲染.这意味着在渲染任何其他"/catalogue/XYZ"个子路由时,不会装载Redux Provider组件和存储.目录react-router-dom@6版本不是真正的1-1转换.

若要修复,应将目录转换为布局管线,该布局管线为其嵌套管线呈现Outlet.目录Home是应在索引路由上渲染的组件.您还需要将Redux存储声明103移动到任何React组件,以便不会在每个渲染周期重新声明is.

例子:

目录

const reducers = combineReducers({
  chapters: playlistReducer,
  people: playlistReducer,
});

const store = createStore(reducers); // <-- declared once

const 目录 = () => {
  ...

  return (
    <Provider store={store}>
      <div className={style.应用程序}>
        <SideBar />
        <目录Header account={{display_name: "User"}}/>
        <Outlet /> // <-- nested routes render content here
        <FooterBar />
      </div>
    </Provider>
  );
};

export default 目录;

应用程序

const 应用程序 = () => {
  ...

  return (
    <React.Fragment>
      <SearchContext.Provider value={searchText}>
        <目录SearchContext.Provider value={searchText}>
          <PlayerContext.Provider value={{ playerItem, setPlayerItem }}>
            <BrowserRouter basename={process.env.PUBLIC_URL}>
              <Routes>
                <Route path="/tier_a" element={<TierA />} />
                <Route path="/tier_b" element={<TierB />} />
                <Route path="catalogue" element={<目录 />}> // <-- 目录 is layout route 
                  <Route
                    index
                    element={(
                      <目录Home // <-- 目录Home is index route
                        chapters={chapters}
                        people={people}
                        posts={posts}
                      />
                    )}
                  />
                  <Route path="search" element={<目录Search />} />
                  <Route path="posts" element={<Post />} />  
                  <Route path="post/:id" element={<PostDetail />} />
                  <Route path="people" element={<People />} />
                  <Route path="chapters" element={<Chapters />} />
                </Route>
                <Route path="/admin" element={<Admin />} />
                <Route path="*" element={<NotFound />} />
              </Routes>
            </BrowserRouter>
          </PlayerContext.Provider>
        </目录SearchContext.Provider>
      </SearchContext.Provider>
    </React.Fragment>
  );
};

export default 应用程序;

Reactjs相关问答推荐

sourceBuffer. appendBuffer成功,但h5视频播放器卡住了

使用Overpass API Endpoint计算 map 上的面积

Tailwind不使用@apply classes构建,并强制使用类似于移动的viewport

导致useState中断的中断模式

如何访问子集合中的文档?

React中的useEffect钩子

在transformResponse中使用来自其他查询的缓存

页面永远加载API/从数据库获取数据

svg每条路径上的波浪动画

警告:遇到两个子元素拥有同一把 keys .键应该是唯一的,以便组件在更新时保持其身份

无法从子组件传递数据到父组件

Zod 验证模式根据另一个数组字段使字段成为必需字段

根据其中的值不同地react setState 更新状态

如何使用 React 更改 Material UI 中 ButtonGroup 的 colored颜色 ?

ReactJS:useMemo 钩子修复了我的无限重新渲染问题而不是 useEffect

Cypress ,重试不再附加到 DOM 的元素

如何在 React 中单击鼠标的位置动态添加 div?

react-admin useGetIdentity 只返回全名,id 未定义 头像未定义

axios post方法中的请求失败,状态码为500错误

React.js 中的页面崩溃(读取未定义的属性)