React アプリケーションには、次の両方の変数があります。
- でグローバル状態として定義され、 setter メソッドを使用してを
App.js
介して他のコンポーネントにグローバルに渡されます。GlobalContext.Provider
- アプリの多くのルートのルート パラメーターとして個別に使用されます。
以下は、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
グローバル状態にはキーvalue
とlabel
がありcompetitionId
、url パラメータの は値と同じ値competition.value
です。
のグローバルな状態値は、ウィジェットを使用してコンポーネントcompetition
で変更されることを意図しています。このウィジェットが切り替えられると、グローバル状態が更新され、フックを使用してアプリを新しいルートにプッシュし、updated を使用してurl パラメーターを設定します。<Navbar>
select
useHistory
competition.value
competitionId
の値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...