web-dev-qa-db-ja.com

React Router with-Ant Design Sider:コンテンツセクションに関連するメニュー項目のコンポーネントを追加する方法

AntDメニューサイダーをタブパネルのように使用しようとしています。

コンテンツ内にコンポーネントを配置して、メニュー項目がクリックされたときにコンテンツパネルが関連するコンポーネントをレンダリングするようにします。

この構造を取得して、各メニュー項目のコンテンツとしてコンポーネントを取得するにはどうすればよいですか?

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;

これをレンダリングしようとしても、エラーはスローされませんが、コンテンツdivが、メニュー項目のコンテンツとして指定したPasswordForgetFormで更新されません。

私は以下のクリスの提案を試しました-これはレイアウトセグメントのさまざまなメニュー項目コンテンツdivのコンポーネントをレンダリングするのにうまく機能しますが、このアプローチの欠点は、ページを更新するたびに、パスがメニューがあるテストページの代わりに、その特定のメニュー項目、およびその関連コンテンツを持つコンテンツコンポーネント。このアプローチが賢明であると承認されている場合、サブセットメニューアイテムのURLに移動するのではなく、元のページでページを更新し続ける方法はありますか?

更新

私はこれを発見しました 文学 。これは私が知っておく必要があることだと思いますが、言語は私には理解できないほど専門的です。誰でもこの主題の簡単な英語版を手伝ってくれる?

また、ポーズを使用してレンダリングを支援する このチュートリアル も見つけました。この構造は私が達成しようとしているものですが、ポーズは廃止されているようです。この結果を得るためにreact-routerを超える必要があるかどうか誰かが知っていますか、または私がreact内に実装するように見える解決策があるか

この example は私が望んでいるものに似ていますが、サイドバーを定義するものは何も見つかりません(これは、この作業を行うために必要な引数のようです)。

この投稿 も見ました。回答の一部はドキュメントのコピーと貼り付けですが、Adam Geringの回答が必要なものに近いのではないかと思います。私は常に/ dashルートにSiderメニューを維持しようとしています。そのURLは変更しないでください。ユーザーがサイダーのどのメニュー項目をクリックしても、/ dashコンポーネントのコンテンツdivを更新して、指定したルートパスでコンポーネントをレンダリングする必要があります。

クリスの提案を適用する

クリスは以下の提案を親切に提供してくれました。試してみましたが、メニュー項目がクリックされたとき(および関連するコンポーネントがコンテンツdivに正しく読み込まれたときに、期待どおりに機能しない状況が発生しましたが、ページを更新すると、更新によってページが読み込まれます。ダッシュボードページのコンテンツdiv内にあるはずのコンポーネントのURL。

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;

私のroutesファイルには、次のものが含まれています。

export const ACCOUNT = '/account';

また、 このチュートリアル -上記で概説したのと同じアプローチを使用しており、ページの更新時にコードが行うのと同じ方法でリダイレクトされません。チュートリアルではBrowserRouterの代わりにRouteを使用していますが、それ以外の点では違いがわかりません。

次の試み

私はこれを見た post (ありがとうMatt)。私はその投稿の提案に従うようにしました。

ダッシュボードページから外部ルーターラッパーを削除しました(ダッシュボードへのルートが設定されているApp.jsの周りにルーターがあります)。

次に、ダッシュボードでコンテンツdivを次のように変更しました。

追加した:

let match = useRouteMatch();

ダッシュボードコンポーネント内のレンダリングメソッドに( ここ のように)。

React-router-domからのimportステートメントにuseRouteMatchを追加しました。

これにより、次のようなエラーが発生します。

エラー:無効なフック呼び出し。フックは、関数コンポーネントの本体の内部でのみ呼び出すことができます。これは、次のいずれかの理由で発生する可能性があります。1. Reactとレンダラー(React DOM)など)のバージョンが一致していない可能性があります。フックのルールを破る

上記のエラーにはもっとメッセージがありますが、リンクが短いため、スタックオーバーフローでは投稿できません

これらの手順で何が間違っているのかはわかりませんが、letステートメントをコメントアウトすると、ページが読み込まれます。

/ Dashboardに移動して[アカウント]をクリックすると、ダッシュボードページのレイアウトにあるコンテンツdiv内にアカウントコンポーネントが表示されることを期待しています。代わりに、localhost3000/accountのページに直接リダイレクトします(ページ参照はありません-これは、ダッシュボードページ内でレンダリングするコンポーネントにすぎません)。

ですから、これは私が始めた問題よりも悪いです-少なくとも最初は、リダイレクトはページの更新時にのみ発生したためです。今ではすぐに起こります。

各種類のルートの例がある this repo を見つけました。私がしていないことが何をしているのか分かりません。

この post は私と同じ問題を抱えているようで、私が試したのと同じアプローチを使用して解決しました。 2018年からの投稿なので、時間の経過によってアプローチが古くなる可能性がありますが、その投稿ソリューションの実装と私の元の試みとの間に違いはありません。

次の試み

私は、リューボミールの この投稿 の答えで機能するアプローチを見つけたと思っていました。

私が持っています:

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

{${this.props.match.url}/account}>アカウント設定

次に、私が持っているこのコンポーネントを表示したいダッシュコンポーネントのdivで:

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

これは機能します。ページを更新すると、正常に機能し続けることができます。

しかし、次のように2番目のメニュー項目を追加すると、

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

/ learnのメニュー項目をクリックすると(およびURLバーが学習に変化する)、ラーニングコンポーネントがレンダリングされる代わりに、アカウントコンポーネントがレンダリングされます。 switchステートメントからアカウントの表示を削除すると、正しい学習コンポーネントを表示できます。

この試みにより、[〜#〜] one [〜#〜 ]メニュー項目のみ。 2番目のメニュー項目を追加した場合、2番目のコンポーネントを正しくレンダリングできる唯一の方法は、最初のメニュー項目を削除することです。正確なパスを持つスイッチを使用しています。

このソリューションで複数のメニュー項目を操作したい。

私はURLのパスを変更しようとしました(例:

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

と同じです:

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

私は このブログ で説明を読みましたが、これらのオプションを完全には理解していません。 これを読む があります。これは、matchステートメントがコンポーネントをレンダリングするためのレガシーメソッドであることを示しています(フックが利用可能になりました)。期待される結果を達成するためにフックを使用する方法を示すトレーニング資料が見つかりません。

8
Mel

この投稿でリュボミールの答えを見つけました。できます。 反応ルーターv4/v5のネストされたルート

メニュー項目のリンクは次のとおりです。

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

表示パスは次のとおりです。

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

コンポーネントの名前の前にコロンがあります。なぜだかわかりません。誰かがこのアプローチが何と呼ばれているのかを知っているなら-私はそれを理解しようとすることができるように参考文献に感謝します。

0
Mel