我有一个React应用程序,有主布局和子"outlet".其中一个渠道是一个用户配置文件管理页面,用户图像可以在这里更新.用户配置文件图像也显示在主布局菜单上.我希望能够调用一个处理程序函数在我的主布局更新图像时,用户改变图像在配置文件出口.

这是我到目前为止的代码.

App.jsx

import { BrowserRouter as Router, Route, Routes, Outlet } from "react-router-dom";
import { AuthProvider } from "./context/AuthContext";

import HomePage from "./pages/HomePage";
import LoginPage from "./pages/LoginPage";
import Profile from "./pages/Profile";
import PrivateRoutes from "./utils/PrivateRoutes";

//Prime React styles
import "primeflex/primeflex.css";
import "primereact/resources/primereact.min.css";
import "primeicons/primeicons.css";

function App() {
  return (
    <div className="App">
      <Router>
        <AuthProvider>
          <Routes>
            <Route path="/login" element={<LoginPage />} />
            <Route element={<PrivateRoutes />}>  
              <Route path="/Profile" element={<Profile />} />
              <Route path="/" element={<HomePage />} />
            </Route>     
          </Routes> 
        </AuthProvider>
      </Router>
    </div>
  );
}

export default App;

PrivateRoutes.jsx

import { Outlet, Navigate } from 'react-router-dom'
import { useContext } from 'react'
import AuthContext from '../context/AuthContext'
import Layout from '../components/Layout';

const MainLayout = () => (
  <>
    <Layout
      childpage={<Outlet handleButtonClicked={Layout.handleButtonClicked />}
    />
  </>
);

const PrivateRoutes = () => {
  let { user } = useContext(AuthContext)
  return user ? <MainLayout /> : <Navigate to="/login" />
}

export default PrivateRoutes

Layout.jsx

import React, { useContext, useState, useEffect } from "react";

import AuthContext from "../context/AuthContext";
import { NavLink } from "react-router-dom";
import useAxios from "../interceptors/useAxios";

const Layout = ({ childpage }) => {
  let { logoutUser } = useContext(AuthContext);
  const { user } = useContext(AuthContext);
  let [image, setimage] = useState("http://localhost:8000/media/default.jpg");
  const api = useAxios();

  useEffect(() => {
    api.post("/api/profile", { username: user.username }).then((response) => {
      setimage("http://localhost:8000" + response.data.image);  
    });
  }, []); // Empty dependency array ensures this runs only on first load

  //***HANDLER*****
  const handleButtonClicked = () => {
    console.log("Button was clicked");
  };
 
  return user ? (
    <div className="min-h-screen flex relative lg:static surface-ground">
      <div
        id="app-sidebar-5"
        className="bg-gray-900 h-screen hidden lg:block flex-shrink-0 absolute lg:static left-0 top-0 z-1 border-right-1 border-gray-800 w-18rem lg:w-7rem select-none"
      >
        <div className="flex flex-column h-full">
          <div
            className="flex align-items-center justify-content-center flex-shrink-0 bg-indigo-500"
            style={{ height: "60px" }}
          >
            <img
              src="/images/logos/hyper-light.svg"
              alt="hyper-light"
              height={30}
            />
          </div>
          <div className="mt-auto mx-3">
            <hr className="mb-3  border-top-1 border-gray-800" />
            <a
              className="p-ripple my-3 flex flex-row lg:flex-column align-items-center cursor-pointer p-3 lg:justify-content-center hover:bg-gray-800 border-round text-gray-300 hover:text-white transition-duration-150 transition-colors w-full"
            >
            <NavLink to="/profile"  activeclassname="active">
                <div className="p-ripple flex flex-row lg:flex-column align-items-center cursor-pointer p-3 lg:justify-content-center hover:bg-gray-800 border-round text-gray-300 hover:text-white transition-duration-150 transition-colors w-full">
                <img
                src={image}
                className="mr-2 lg:mr-0"
                style={{
                  width: "32px",
                  height: "32px",
                }}
                alt="avatar-f-1"
              />
                </div>
              </NavLink>
            </a>
          </div>
        </div>
      </div>
      <div className="min-h-screen flex flex-column relative flex-auto">
        <div
          className="flex justify-content-between align-items-center px-5 surface-section relative lg:static border-bottom-1 surface-border"
          style={{ height: "60px" }}
        >
          <div className="flex">
    
          </div>

          <ul
            className="list-none p-0 m-0 hidden lg:flex lg:align-items-center select-none lg:flex-row
                    surface-section border-1 lg:border-none surface-border right-0 top-100 z-1 shadow-2 lg:shadow-none absolute lg:static"
          >
            <li>
              <a
                onClick={logoutUser}
                className="p-ripple flex p-3 lg:px-3 lg:py-2 align-items-center text-600 hover:text-900 hover:surface-100 font-medium border-round cursor-pointer
                            transition-duration-150 transition-colors"
              >
                <i className="pi pi-sign-out text-base lg:text-2xl mr-2 lg:mr-0 p-overlay-badge"></i>
                <span className="block lg:hidden font-medium">Log out</span>
              </a>
            </li>
          </ul>
        </div>
      
        <div className="p-5 flex flex-column flex-auto max-h-screen">
           <div className="surface-card p-4 shadow-2 border-round overflow-y-auto"> 
            <main>{childpage}</main>
          </div>
        </div>
      </div>
    </div>
  ) : (
    <div>
      <p>You are not logged in, redirecting...</p>
    </div>
  );
};

export default Layout;

Profile.jsx Profile.jsx

import React from 'react';

const Profile = ({ handleButtonClicked  }) => {
  return (
    <button onClick={ handleButtonClicked }>Trigger Handler in Layout</button>
  );
};

export default Profile;

但是,从PrivateRoutes.jsx抛出的错误是handlebuttonclick是未定义的.

I wish to call my handler which is defined in Layout.jsx from Profile.jsx Profile.jsx.

Profile.jsx jsx是我的一个'childpage',它被layout.jsx包装

推荐答案

您可以通过Outlet组件提供的上下文向派生路由组件提供handleButtonClicked回调函数,该上下文可以在路由组件中通过useOutletContext钩子访问.

更新Layout以直接呈现Outlet并提供回调函数.

import React, { useContext, useState, useEffect } from "react";
import AuthContext from "../context/AuthContext";
import { NavLink, Outlet } from "react-router-dom";
import useAxios from "../interceptors/useAxios";

const Layout = () => {
  ...

  const handleButtonClicked = () => {
    console.log("Button was clicked");
  };
  
  return user ? (
    <div className="....">
      ...
      <div className="....">
        ...
      
        <div className="....">
          <div className="...."> 
            <main>
              <Outlet context={{ handleButtonClicked }}
            </main>
          </div>
        </div>
      </div>
    </div>
  ) : (
    ...
  );
};

export default Layout;
const MainLayout = () => (
  <>
    <Layout />
  </>
);
import React from 'react';
import { useOutletContext } from 'react-router-dom';

const Profile = () => {
  const { handleButtonClicked } = useOutletContext();

  return (
    <button onClick={handleButtonClicked}>
      Trigger Handler in Layout
    </button>
  );
};

export default Profile;

Javascript相关问答推荐

RxJS setTimeout操作符等效

如何在angular中从JSON值添加动态路由保护?

数字时钟在JavaScript中不动态更新

如何在模块层面提供服务?

为什么按钮会随浮动属性一起移动?

当Redux提供程序访问Reduxstore 时,可以安全地从Redux提供程序外部调用钩子?

如何使用子字符串在数组中搜索重复项

在forEach循环中获取目标而不是父对象的属性

如何发送从REST Api收到的PNG数据响应

钛中的onClick事件需要在两次点击之间等待几秒钟

为什么我的按钮没有从&q;1更改为&q;X&q;?

有效路径同时显示有效路径组件和不存在的路径组件

在表单集中保存更改时删除';禁用';

在不扭曲纹理的情况下在顶点着色器中旋转UV

构建器模式与参数对象输入

未捕获的不变违规:即使在使用DndProvider之后也应使用拖放上下文

在单击按钮时生成多个表单时的处理状态

正则表达式以确定给定文本是否不只包含邮箱字符串

使用jQuery每隔几秒钟突出显示列表中的不同单词

观察子组件中的@Output事件emits 器?