React Router with - Ant Design Sider: cách điền phần nội dung với các thành phần cho mục menu có liên quan


8

Tôi đang cố gắng sử dụng trình đơn menu AntD như bảng điều khiển tab.

Tôi muốn đặt các thành phần bên trong nội dung để bảng nội dung hiển thị thành phần liên quan khi nhấp vào một mục menu.

Làm cách nào để có được cấu trúc này để lấy các thành phần làm nội dung cho từng mục menu?

import React from 'react';
import { compose } from 'recompose';
import { Divider, Layout, Card, Tabs, Typography, Menu, Breadcrumb, Icon } from 'antd';
import { PasswordForgetForm } from '../Auth/Password/Forgot';


const { Title } = Typography
const { TabPane } = Tabs;
const { Header, Content, Footer, Sider } = Layout;
const { SubMenu } = Menu;


class Dashboard extends React.Component {
  state = {
    collapsed: false,
  };

  onCollapse = collapsed => {
    console.log(collapsed);
    this.setState({ collapsed });
  };

  render() {
    return (
      <Layout style={{ minHeight: '100vh' }}>
        <Sider collapsible collapsed={this.state.collapsed} onCollapse={this.onCollapse}>
          <div  />
          <Menu theme="light" defaultSelectedKeys={['1']} mode="inline" >

            <Menu.Item key="1">
              <Icon type="fire" />
              <span>Next item</span>
              <PasswordForgetForm />
            </Menu.Item>  
            <Menu.Item key="2">
              <Icon type="fire" />
              <span>Next item</span>
              <Another component to render in the content div />
            </Menu.Item>

          </Menu>
        </Sider>
        <Layout>
          <Header style={{ background: '#fff', padding: 0 }} />
          <Content style={{ margin: '0 16px', background: '#fff' }}>

            <div style={{ padding: 24, background: '#fff', minHeight: 360 }}>
            RENDER RELEVANT COMPONENT HERE BASED ON MENU ITEM SELECTED
            </div>
          </Content>
          </Layout>
      </Layout>
    );
  }
}

export default Dashboard;

Khi tôi cố gắng kết xuất cái này, không có lỗi nào được đưa ra, nhưng div nội dung không cập nhật với PasswordForgetForm mà tôi đã chỉ định làm nội dung cho mục menu.

Tôi đã thử đề xuất của Chris bên dưới - hoạt động tốt để hiển thị thành phần cho từng div nội dung mục menu khác nhau trong phân đoạn bố cục, tuy nhiên - nhược điểm của phương pháp này là với mỗi lần làm mới trang, đường dẫn đến thành phần nội dung cho mục menu cụ thể đó, thay vì trang thử nghiệm có menu trên đó - và thành phần nội dung có nội dung liên quan đó. Nếu cách tiếp cận này được xác nhận là hợp lý, có cách nào để giữ cho trang được làm mới trên trang gốc, thay vì cố gắng đi đến một url của mục menu phụ?

Cập nhật

Tôi tìm thấy tài liệu này . Tôi nghĩ rằng đây có thể là những gì tôi cần biết, nhưng ngôn ngữ quá kỹ thuật để tôi hiểu. Bất cứ ai có thể giúp với một phiên bản tiếng Anh đơn giản của vấn đề này?

Tôi cũng tìm thấy hướng dẫn này sử dụng Pose để giúp kết xuất. Trong khi cấu trúc này là những gì tôi đang cố gắng đạt được, có vẻ như Pose đã bị từ chối. Có ai biết nếu cần phải vượt ra ngoài bộ định tuyến phản ứng để có được kết quả này, hoặc có một giải pháp nào trong phản ứng mà tôi có thể tìm cách thực hiện không?

Đây ví dụ tương tự như những gì tôi muốn, nhưng tôi không thể tìm thấy bất cứ điều gì mà định nghĩa sidebar (mà có vẻ là một cuộc tranh cãi đó là cần thiết để làm công việc này).

Tôi cũng đã thấy bài này . Trong khi một số câu trả lời là một bản sao và dán các tài liệu, tôi tự hỏi liệu câu trả lời của Adam Gering có gần với những gì tôi cần không. Tôi đang cố gắng giữ menu Sider trên tuyến / dash mọi lúc. Url đó không nên thay đổi - bất kể mục menu nào trong sider người dùng nhấp vào NHƯNG div nội dung trong thành phần / dash sẽ được cập nhật để hiển thị thành phần tại đường dẫn tôi đã chỉ định.

ÁP DỤNG TUYỆT VỜI CỦA CHRIS

Chris đã vui lòng đưa ra một đề nghị dưới đây. Tôi đã thử nó, nhưng tình huống mà nó không thực hiện như mong muốn là khi nhấp vào mục menu (và thành phần có liên quan tải chính xác vào div nội dung, nhưng nếu tôi làm mới trang, làm mới sẽ cố tải một trang bằng một url dành cho thành phần được cho là nằm trong div nội dung trên trang bảng điều khiển.

import React from 'react';
import {
    BrowserRouter as Router,
    Route,
    Link,
    Switch,

  } from 'react-router-dom';
import * as ROUTES from '../../constants/Routes';
import { compose } from 'recompose';
import { Divider, Layout, Card, Tabs, Typography, Menu, Breadcrumb, Icon } from 'antd';
import { withFirebase } from '../Firebase/Index';
import { AuthUserContext, withAuthorization, withEmailVerification } from '../Session/Index';

// import UserName from '../Users/UserName';
import Account from '../Account/Index';
import Test from '../Test/Index';



const { Title } = Typography
const { TabPane } = Tabs;
const { Header, Content, Footer, Sider } = Layout;
const { SubMenu } = Menu;


class Dashboard extends React.Component {
  state = {
    collapsed: false,
  };

  onCollapse = collapsed => {
    console.log(collapsed);
    this.setState({ collapsed });
  };

  render() {
    const {  loading } = this.state;
    // const dbUser = this.props.firebase.app.snapshot.data();
    // const user = Firebase.auth().currentUser;
    return (
    <AuthUserContext.Consumer>
      {authUser => (  

        <div>    
         {authUser.email}
          <Router>  
            <Layout style={{ minHeight: '100vh' }}>
              <Sider collapsible collapsed={this.state.collapsed} onCollapse={this.onCollapse}>
                <div  />
                <Menu theme="light" defaultSelectedKeys={['1']} mode="inline" >
                  <SubMenu
                    key="sub1"
                    title={
                      <span>
                      <Icon type="user" />
                      <span>Profile</span>
                      </span>
                    }
                  >

                      <Menu.Item key="2"><Link to={ROUTES.ACCOUNT}>Account Settings</Link></Menu.Item>


                      <Menu.Item key="3"><Link to={ROUTES.TEST}>2nd content component</Link></Menu.Item>
</SubMenu>

                </Menu>
              </Sider>
              <Layout>

                <Header>                </Header>      
                <Content style={{ margin: '0 16px', background: '#fff' }}>

                  <div style={{ padding: 24, background: '#fff', minHeight: 360 }}>
                      <Switch>
                          <Route path={ROUTES.ACCOUNT}>
                          <Account />
                          </Route>
                          <Route path={ROUTES.TEST}>
                          < Test />
                          </Route>

                      </Switch>    
                  </div>
                </Content>
                <Footer style={{ textAlign: 'center' }}>


                 test footer
                </Footer>
              </Layout>
            </Layout>
          </Router>  
        </div>
      )}
    </AuthUserContext.Consumer>  
    );
  }
}

export default Dashboard;

Trong tệp tuyến đường của tôi, tôi có:

export const ACCOUNT = '/account';

Tôi cũng đã tìm thấy hướng dẫn này - sử dụng cách tiếp cận tương tự được nêu ở trên - và không được chuyển hướng theo cùng cách mà mã của tôi thực hiện khi làm mới trang. Hướng dẫn sử dụng Route thay vì BrowserRouter - nhưng nếu không thì tôi không thể thấy bất kỳ sự khác biệt nào.

TIẾP THEO TIẾP THEO

Tôi thấy bài này (cảm ơn Matt). Tôi đã cố gắng làm theo những gợi ý trong bài viết đó.

Tôi đã xóa trình bao bọc Bộ định tuyến bên ngoài khỏi trang Bảng điều khiển (có Bộ định tuyến xung quanh App.js, nơi đặt tuyến đường đến Bảng điều khiển được thiết lập).

Sau đó, trong Bảng điều khiển của tôi, tôi đã thay đổi div Nội dung thành:

Tôi đã thêm:

let match = useRouteMatch();

đến phương thức kết xuất bên trong thành phần Bảng điều khiển của tôi (như được hiển thị ở đây ).

Tôi đã thêm useRouteMatch vào câu lệnh nhập của mình từ Reac-router-dom.

Điều này tạo ra một lỗi cho biết:

Lỗi: Cuộc gọi hook không hợp lệ. Móc chỉ có thể được gọi bên trong cơ thể của một thành phần chức năng. Điều này có thể xảy ra vì một trong những lý do sau: 1. Bạn có thể có các phiên bản không phù hợp của React và trình kết xuất (như React DOM) 2. Bạn có thể đang phá vỡ Quy tắc của móc

Có nhiều thông báo hơn trong lỗi ở trên nhưng stack overflow sẽ không cho phép tôi đăng nó vì nó có một liên kết ngắn

Tôi không biết mình đã làm gì sai trong các bước này, nhưng nếu tôi nhận xét câu lệnh let, trang sẽ tải.

Khi tôi truy cập / Bảng điều khiển và nhấp vào "tài khoản", tôi hy vọng thành phần tài khoản sẽ hiển thị bên trong div nội dung tôi có trong bố cục trên trang Bảng điều khiển. Thay vào đó, nó chuyển hướng trực tiếp đến một trang tại localhost3000 / tài khoản (không có tham chiếu trang - nó chỉ là một thành phần để hiển thị bên trong trang Bảng điều khiển).

Vì vậy, điều này còn tồi tệ hơn vấn đề tôi bắt đầu - vì ít nhất khi bắt đầu, việc chuyển hướng chỉ xảy ra khi làm mới trang. Bây giờ nó xảy ra ngay lập tức.

Tôi tìm thấy repo này có ví dụ về từng loại tuyến đường. Tôi không thể thấy những gì nó đang làm mà tôi không.

Bài đăng này dường như đã có cùng một vấn đề với tôi và đã giải quyết nó bằng cách sử dụng tương tự như tôi đã thử. Đó là một bài đăng từ năm 2018 vì vậy thời gian trôi qua có thể khiến cách tiếp cận trở nên lỗi thời - nhưng tôi không thể thấy bất kỳ sự khác biệt nào giữa những gì giải pháp bài đăng đó thực hiện và nỗ lực ban đầu của tôi.

TIẾP THEO TIẾP THEO

Tôi đã nghĩ rằng tôi đã tìm thấy một cách tiếp cận hoạt động trong câu trả lời của Lyubomir trên bài đăng này .

Tôi có:

<Menu.Item key="2">
                      <Link to=

{ ${this.props.match.url}/account}> Cài đặt tài khoản

Sau đó, trong div trên thành phần dash nơi tôi muốn hiển thị thành phần này tôi có:

<div>
                      <Switch>
                          <Route exact path={`${this.props.match.url}/:account`} component={Account} />

Những công việc này. Khi làm mới trang, tôi có thể giữ mọi thứ hoạt động như bình thường.

TUY NHIÊN, khi tôi thêm một mục menu thứ hai với:

<Menu.Item key="16">
                    <Link to={`${this.props.match.url}/learn`}>
                      <Icon type="solution" />
                      <span>Lern</span>
                    </Link>  
                  </Menu.Item>

Thay vì hiển thị thành phần Học tập khi mục menu cho / learn được nhấp (và thanh url thay đổi để tìm hiểu), thành phần Tài khoản được hiển thị. Nếu tôi xóa màn hình tài khoản khỏi câu lệnh chuyển đổi, thì tôi có thể hiển thị thành phần Học tập chính xác.

Với nỗ lực này, tôi có các mục menu hoạt động để khớp với phần mở rộng url của Bảng điều khiển (ví dụ: localhost / dash / account hoặc localhost / dash / learn) chỉ cho MỘT mục menu. Nếu tôi thêm một mục menu thứ hai, cách duy nhất tôi có thể kết xuất chính xác thành phần thứ 2, là bằng cách xóa mục menu đầu tiên. Tôi đang sử dụng chuyển đổi với các đường dẫn chính xác.

Tôi muốn giải pháp này hoạt động với nhiều mục menu.

Tôi đã thử đường dẫn xen kẽ cho url (ví dụ:

<Link to={`${this.props.match.url}/learn`}>

giống như:

<Link to={`${this.props.match.path}/learn`}>

Tôi đã đọc lời giải thích trong blog này và trong khi tôi hoàn toàn không hiểu các tùy chọn này. Tôi đã đọc điều này . Nó cho thấy câu lệnh khớp bây giờ là một phương thức kế thừa để kết xuất các thành phần (bây giờ có sẵn các hook). Tôi không thể tìm thấy bất kỳ tài liệu đào tạo nào cho thấy cách sử dụng móc để đạt được kết quả mong đợi.


Vui lòng bao gồm các PasswordForgottenFormthành phần là tốt.
Alexanderr

Nó chỉ là một thành phần const với một hình thức trong đó. Mỗi mục menu có một thành phần riêng (một số là thành phần lớp) được hiển thị trong div nội dung của phần bố cục trên thành phần thử nghiệm.
Mel

Câu trả lời:


4

Giải pháp tốt hơn là sử dụng React Router <Link>để làm cho mỗi mục menu liên kết đến một đường dẫn cụ thể, sau đó trong nội dung, sử dụng <Switch>để kết xuất thành phần tương ứng. Đây là doc: React router

Kết xuất với bộ định tuyến React

<Router>
  <Layout style={{ minHeight: "100vh" }}>
    <Sider
      collapsible
      collapsed={this.state.collapsed}
      onCollapse={this.onCollapse}
    >
      <div />
      <Menu theme="light" defaultSelectedKeys={["1"]} mode="inline">
        <Menu.Item key="1">
          // Add a react router link here
          <Link to="/password-forget-form">
            <Icon type="fire" />
            <span>Next item</span>
          </Link>
        </Menu.Item>
        <Menu.Item key="2">
          // Add another react router link
          <Link to="/next-item">
            <Icon type="fire" />
            <span>Next item</span>
          </Link>
        </Menu.Item>
      </Menu>
    </Sider>
    <Layout>
      <Header style={{ background: "#fff", padding: 0 }} />
      <Content style={{ margin: "0 16px", background: "#fff" }}>
        <div style={{ padding: 24, background: "#fff", minHeight: 360 }}>
          // Render different components based on the path
          <Switch>
            <Route path="/password-forget-form">
              <PasswordForgetForm />
            </Route>
            <Route path="/next-item">
              <Another component to render in the content div />
            </Route>
          </Switch>
        </div>
      </Content>
    </Layout>
  </Layout>
</Router>;

Kết xuất bằng phím Menu

App.js

import React, { useState } from "react";
import { Layout } from "antd";
import Sider from "./Sider";
import "./styles.css";

const { Content } = Layout;
export default function App() {
  const style = {
    fontSize: "30px",
    height: "100%",
    display: "flex",
    alignItems: "center",
    justifyContent: "center"
  };

  const components = {
    1: <div style={style}>Option 1</div>,
    2: <div style={style}>Option 2</div>,
    3: <div style={style}>Option 3</div>,
    4: <div style={style}>Option 4</div>
  };

  const [render, updateRender] = useState(1);

  const handleMenuClick = menu => {
    updateRender(menu.key);
  };

  return (
    <div className="App">
      <Layout style={{ minHeight: "100vh" }}>
        <Sider handleClick={handleMenuClick} />
        <Layout>
          <Content>{components[render]}</Content>
        </Layout>
      </Layout>
    </div>
  );
}

Sider.js

import React from "react";
import { Menu, Layout, Icon } from "antd";

const { SubMenu } = Menu;

export default function Sider(props) {
  const { handleClick } = props;
  return (
    <Layout.Sider>
      <Menu theme="dark" mode="inline" openKeys={"sub1"}>
        <SubMenu
          key="sub1"
          title={
            <span>
              <Icon type="mail" />
              <span>Navigation One</span>
            </span>
          }
        >
          <Menu.Item key="1" onClick={handleClick}>
            Option 1
          </Menu.Item>
          <Menu.Item key="2" onClick={handleClick}>
            Option 2
          </Menu.Item>
          <Menu.Item key="3" onClick={handleClick}>
            Option 3
          </Menu.Item>
          <Menu.Item key="4" onClick={handleClick}>
            Option 4
          </Menu.Item>
        </SubMenu>
      </Menu>
    </Layout.Sider>
  );
}

Chỉnh sửa antd-menu-click-render


Bình luận không dành cho thảo luận mở rộng; cuộc trò chuyện này đã được chuyển sang trò chuyện .
Samuel Liew

Cảm ơn cả Chris và Matt. Tôi rất trân trọng tất cả sự giúp đỡ trong việc cố gắng giải quyết điều này.
Mel

0

Tôi tìm thấy câu trả lời của Lyubomir trên bài đăng này. Nó hoạt động. Các tuyến lồng nhau với bộ định tuyến phản ứng v4 / v5

Liên kết mục menu là:

<Menu.Item key="2">
                      <Link to=
                       {`${this.props.match.url}/account`}>
                        Account
                      </Link>
                    </Menu.Item>

Đường dẫn hiển thị là:

<Route exact path={`${this.props.match.path}/:account`} component={Account} />

Có một dấu hai chấm trước tên của thành phần. Không chắc chắn lý do tại sao. Nếu bất cứ ai biết cách tiếp cận này được gọi là gì - tôi rất biết ơn về một tài liệu tham khảo để tôi có thể cố gắng hiểu nó.


Thật ra - tôi đã nói chuyện sớm. Trong khi điều này không hoạt động. Có một trục trặc. Nó chỉ hoạt động với một liên kết. Nếu tôi thêm tuyến đường vào liên kết menu thứ hai (được gọi là Học tập), theo cách tiếp cận tương tự, tôi phải xóa màn hình cho Tài khoản để có thể hiển thị thành phần Học tập. Nếu tôi cố giữ cả hai, thành phần tài khoản sẽ hiển thị ngay cả khi tôi đã yêu cầu thành phần Học tập.
Mel

Sử dụng :là một paramský tự đại diện. Như vậy /app/accountlà giống như /app/sdfsfjfdjfjfdnfjnsdfjn, đó là giống như /app/doefmdvà như vậy. Nó chỉ gán chuỗi cho một biến params được khai báo - xem ví dụ ở đây: Reacttraining.com/react-router/web/example/url-params , khai báo chuỗi là params :id). Nếu bạn muốn sử dụng các thông số, bạn sẽ cần sử dụng đường dẫn Regex (cho nhiều thông số) hoặc làm cho các đường dẫn của bạn trở nên độc đáo hơn /app/dashboardso với /app/settings/5e0b97003e95542de2d8e3a1, đó 5e0b97003e95542de2d8e3a1là một thông số duy nhất id.
Matt Carlotta

Nói tóm lại, /app/:idsẽ phù hợp với cùng một tuyến đường /app/:account, sẽ phù hợp với cùng một tuyến đường với /app/settings. Do thẻ đại diện param, chúng không đủ độc đáo để so khớp.
Matt Carlotta

@MattCarlotta - nếu bạn muốn điểm - Tôi rất vui khi đưa chúng cho bạn.
Mel

Tôi ổn. Cảm ơn. Nếu tất cả các câu hỏi của bạn đã được trả lời, bạn có thể loại bỏ tiền thưởng.
Matt Carlotta
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.