0

React アプリケーションには、次の両方の変数があります。

  1. でグローバル状態として定義され、 setter メソッドを使用してをApp.js介して他のコンポーネントにグローバルに渡されます。GlobalContext.Provider
  2. アプリの多くのルートのルート パラメーターとして個別に使用されます。

以下は、App.jsファイルの関連セクションの短いコード スニペットです。

import React, { useState, useEffect } from 'react';
import GlobalContext from './context/GlobalContext';
import OtherComponents...

function App() {
    const [competition, setCompetition] = useState({ value: 15, label: 'Season 1' });

    return (
        <GlobalContext.Provider value={{ // Pass Global State Through To Entire App
            competition, setCompetition
        }}>
            <Navbar />
            <Switch>
                <Route exact path='/' render={(props) => <HomePage {...props} />} />
                <Route exact path='/stats' component={StatsPage} />
                <Route exact path='/about' component={AboutUs} />
                <Route exact path='/persons/:competitionId/ component={PersonsComponent} />
                <Route exact path='/teams/:competitionId component={TeamsComponent} />
            </Switch>
        </GlobalContext.Provider>
    );
}

export default App;

competitionグローバル状態にはキーvaluelabelがありcompetitionId、url パラメータの は値と同じ値competition.valueです。

のグローバルな状態値は、ウィジェットを使用してコンポーネントcompetitionで変更されることを意図しています。このウィジェットが切り替えられると、グローバル状態が更新され、フックを使用してアプリを新しいルートにプッシュし、updated を使用してurl パラメーターを設定します。<Navbar>selectuseHistorycompetition.valuecompetitionId

の値competitionは、アプリケーションの多くのコンポーネントで必要です。これには、url パラメーターがないコンポーネント (<HomePage>コンポーネント内など) も含まれます。このため、他のすべてのコンポーネントに渡されるグローバル変数として必要であると感じています。変数はuseContextフックを使用してどこからでも簡単にアクセスできるため、これは私たちにとっても非常に便利です。

ただし、この値はURL パラメーターにも必要なようです。これらのコンポーネントは、渡されたものに基づいてさまざまなデータを取得competitionIdします。それらが URL パラメーターに含まれていることは、アプリのルーティングの大部分を占めています。

問題は、ユーザーが Web サイトの URL を手動で変更できることです。これにより、変数のグローバルな状態を変更せずに URL パラメータを変更できます。ウィジェットではなく手動で URL を変更するとselect、グローバル状態と URL パラメータが同期しなくなります...

編集:select値を切り替えるために使用するコンポーネントは次のとおりcompetitionです(投稿が長くなって申し訳ありません)。この選択は Navbar に表示され、外部にあるためグローバルにアクセスできます<Switch>

function CompetitionSelect({ currentPath }) {
    // Grab History In Order To Push To Selected Pages
    let history = useHistory();
    let { competition, setCompetition } = useContext(GlobalContext);

    // Fetch Data on All Competitions (dropdown options)
    const competitionInfosConfig = {};
    const [competitionInfos, isLoading1, isError1] = useInternalApi('competitionInfo', [], competitionInfosConfig);

    // Messy digging of competitionId out of current path.
    let competitionIds = competitionInfos.map(row => row.competitionId);
    let pathCompetitionId = null;
    competitionIds.forEach(id => {
        if (currentPath.includes(`/${id}/`)) {
            pathCompetitionId = id;
        }
    });

    // Messy Handling State/Params Out Of Sync
    if (pathCompetitionId === null) {
        console.log('Not a page where testing is needed');
    }
    else if (competition.value !== pathCompetitionId) {
        console.log('WERE OUT OF SYNC...');
        let correctGlobalState = { value: pathCompetitionId, label: 'Label Set' };
        setCompetition(correctGlobalState);
    } else {
        console.log('IN SYNC: ', competition.value, ' == ', pathCompetitionId);
    }

    // Handle updating state + pushing to new route
    const handleSelect = (event) => {
        let oldPath = JSON.parse(JSON.stringify(history.location.pathname));
        let newPath = '';
        competitionIds.forEach(id => {
            if (oldPath.includes(`/${id}/`)) {
                newPath = oldPath.replace(`/${id}/`, `/${event.value}/`)
            }
        });

        if (newPath !== '') {
            setCompetition(event);
            history.push(newPath);
        }
    };

    // Create The Select
    const competitionSelect =
        (<Select
            styles={appSelectStyles}
            value={competition}
            options={competitionInfos}
            onChange={handleSelect}
            placeholder={'Select Competition'}
        />);

    return (
        {competitionSelect}
    );
}

export default CompetitionSelect;

このコンポーネントは、技術的にはif, if else, else句の非同期の問題を解決しますが、が呼び出されるたびsetCompetition(correctGlobalState)に、React は次の警告メッセージをスローします。

Warning: Cannot update a component (アプリ) while rendering a different component (コンペティション選択). To locate the bad setState() call inside コンペティション選択, follow the stack trace as described...

4

1 に答える 1