🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

Q&A

解決済

1回答

2500閲覧

checkboxでAPIを叩くときにチェックを外したらAPIで取得した値を削除する方法

kAAAAA

総合スコア1

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

0グッド

1クリップ

投稿2021/02/28 11:59

https://opendata.resas-portal.go.jp/docs/api/v1/prefectures.html
現在こちらのAPIを使って県名のチェックボックスをチェックしたらその県名の県名コードから人口を取り出すAPIを叩いてグラフに表示させるwebページをReactを用いて開発をしております。
ビジュアルは以下の通りです。

イメージ説明

そこで質問なのですが

ABCD…のように他の県名のボタンを押したらそのグラフを動的に表示してチェックボックスを外した箇所だけのデータを消す方法をご教授願いたいです。
おそらくチェックボックスのkeyによって消すデータを決定するしかないと思うのですが、何通りの方法も試したのですが答えにたどり着くことができませんでした。

index.tsx

1import React, { useEffect, useState } from "react"; 2import { getPrefectureData } from "./api/prefecture"; 3import { getPopulationData } from "./api/population"; 4import HighchartsReact from "highcharts-react-official"; 5 6interface PrefectureInfo { 7 prefCode: number; 8 prefName: string; 9} 10type PopulationInfo = { 11 year: number; 12 value: number; 13}; 14 15export default function index() { 16 const [prefectures, setPrefectures] = useState<PrefectureInfo[]>([]); 17 const [populations, setPopulations] = useState<PopulationInfo[]>([]); 18 const [selectedPopulations, setSelectedPopulations] = useState<number[]>([]); 19 const [checkedIds, setCheckedIds] = useState<number[]>([]); 20 const [checkedName, setCheckedName] = useState<string>(); 21 const [graphData, setGraphData] = useState< 22 { data: number[]; name: string | undefined }[] 23 >([]); 24 25 const options = { 26 chart: { 27 type: "spline", 28 }, 29 title: { 30 text: "人口グラフ", 31 }, 32 xAxis: { 33 categories: [ 34 "1960", 35 "1965", 36 "1970", 37 "1975", 38 "1980", 39 "1985", 40 "1990", 41 "1995", 42 "2000", 43 "2005", 44 "2010", 45 "2015", 46 "2020", 47 "2025", 48 "2030", 49 "2035", 50 "2040", 51 "2045", 52 ], 53 }, 54 series: graphData, 55 }; 56 57 //こちらで県名のuAPIを取得しております。 58 useEffect(() => { 59 const fetchPrefecture = async () => { 60 const res = getPrefectureData.FetchPrefecture(); 61 62 await res.then((data) => { 63 setPrefectures(data); 64 }); 65 }; 66 fetchPrefecture(); 67 }, []); 68 69 70 useEffect(() => { 71 const fetchPopulation = async () => { 72 //こちらで自分がチェックした値のcitycodeでresasのAPIを叩いて人口をgetします。 73 74 const res = await Promise.all( 75 checkedIds?.map( 76 async (id: number) => await getPopulationData.FetchPopulation(id) 77 ) 78 ); 79 //もしレスポンスがなかったら????にします 80 if (res.length === 0) { 81 setPopulations([]); 82 }    83 //こちらで人口のデータを最終的にstateで保管します。 84 await Promise.all(res.map((item) => setPopulations(item[0].data))); 85 }; 86 fetchPopulation(); 87 }, [checkedIds]); 88 89 useEffect(() => { 90 //保管した人口のstateのをhichartの形式(data:[11,22,33])のようなにするために人口データを加工します 91 const data = populations?.map((item) => { 92 return item.value; 93 }); 94 //もし加工してstateで管理します。こちらの値をグラフで表示します。 95 if (data && checkedName) { 96 setGraphData([...graphData, { data, name: checkedName }]); 97 } 98 99 if (populations.length === 0) { 100 setGraphData([]); 101 } 102 }, [populations]); 103 104 const handleChange = ( 105 e: React.FormEvent<HTMLInputElement>, 106 prefectureName: string 107 ) => { 108 if ((e.target as HTMLInputElement).checked === true) { 109 const deleteDuplicateId = new Set([...checkedIds]); 110 setCheckedIds([...deleteDuplicateId, Number(e.currentTarget.value)]); 111 112 setCheckedName(prefectureName); 113 114 } else if ((e.target as HTMLInputElement).checked === false) { 115 const removedId = Number(e.currentTarget.value); 116 const newIds = checkedIds.filter((value) => { 117 return value !== removedId; 118 }); 119 setCheckedIds(newIds); 120 121 setCheckedName(""); 122 } 123 }; 124 125 return ( 126 <div className="mt-10"> 127 <h1 className="w-9/12 m-auto"> 128 <span className="border-2 border-black">都道府県</span> 129 </h1> 130 <div className="flex flex-wrap w-9/12 m-auto"> 131 {prefectures?.map((item) => { 132 return ( 133 <label key={item.prefCode} className="flex mr-14 mt-4"> 134 <input 135 type="checkbox" 136 value={item.prefCode} 137 onChange={(e) => handleChange(e, item.prefName)} 138 /> 139 <div>{item.prefName}</div> 140 </label> 141 ); 142 })} 143 </div> 144 <div className="w-9/12 m-auto mt-28"> 145 <HighchartsReact constructorType={"chart"} options={options} /> 146 </div> 147 </div> 148 ); 149} 150

populationAPI

1import { PopulationInfo } from "./types"; 2 3class Population { 4 FetchPopulation = async (code: number) => { 5 const res = await fetch( 6 `https://opendata.resas-portal.go.jp/api/v1/population/composition/perYear?prefCode=${code}`, 7 { 8 method: "GET", 9 headers: { 10 "X-API-KEY": `${process.env.NEXT_PUBLIC_API_KEY}`, 11 }, 12 } 13 ); 14 return await res.json().then((item: PopulationInfo) => item.result.data); 15 }; 16} 17 18export const getPopulationData = new Population();

PrefecutureAPI

1import { PrefectureInfo } from "./types"; 2 3class Prefecutures { 4 FetchPrefecture = async () => { 5 const res = await fetch( 6 "https://opendata.resas-portal.go.jp/api/v1/prefectures", 7 { 8 method: "GET", 9 headers: { 10 "X-API-KEY": `${process.env.NEXT_PUBLIC_API_KEY}`, 11 }, 12 } 13 ); 14 return await res.json().then((item: PrefectureInfo) => item.result); 15 }; 16} 17 18export const getPrefectureData = new Prefecutures(); 19

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

こんな感じでいかがでしょうか?

js

1export default function App() { 2 const [prefectures, setPrefectures] = useState<PrefectureInfo[]>([]); 3 const [checkedPrefCodes, setCheckedPrefCodes] = useState<number[]>([]); 4 const [loadedPrefData, setLoadedPrefData] = useState(new Map<number, number[]>()); 5 6 const graphData: { name: string, data: number[] }[] = checkedPrefCodes 7 .map(code => prefectures.find(pref => pref.prefCode === code)) 8 .filter(pref => pref !== undefined && loadedPrefData.has(pref.prefCode)) 9 .map(pref => ({ name: pref!.prefName, data: [...loadedPrefData.get(pref!.prefCode)!] })); 10 11 const options = { 12 chart: { 13 type: "spline", 14 }, 15 title: { 16 text: "人口グラフ", 17 }, 18 xAxis: { 19 categories: [ 20 "1960", 21 "1965", 22 "1970", 23 "1975", 24 "1980", 25 "1985", 26 "1990", 27 "1995", 28 "2000", 29 "2005", 30 "2010", 31 "2015", 32 "2020", 33 "2025", 34 "2030", 35 "2035", 36 "2040", 37 "2045", 38 ], 39 }, 40 series: graphData, 41 }; 42 43 useEffect(() => { 44 getPrefectureData.FetchPrefecture().then(res => setPrefectures(res)); 45 }, []); 46 47 const handleChange = (checked: boolean, prefCode: number) => { 48 if (checked) { 49 if (!checkedPrefCodes.includes(prefCode)) { 50 setCheckedPrefCodes([...checkedPrefCodes, prefCode]); 51 } 52 if (!loadedPrefData.has(prefCode)) { 53 getPopulationData.FetchPopulation(prefCode).then(res => { 54 setLoadedPrefData(oldData => { 55 const newData = new Map(oldData); 56 newData.set(prefCode, res[0].data.map(item => item.value)); 57 return newData; 58 }); 59 }); 60 } 61 } else { 62 setCheckedPrefCodes(checkedPrefCodes.filter(code => code !== prefCode)); 63 } 64 }; 65 66 return ( 67 <div className="mt-10"> 68 <h1 className="w-9/12 m-auto"> 69 <span className="border-2 border-black">都道府県</span> 70 </h1> 71 <div className="flex flex-wrap w-9/12 m-auto"> 72 {prefectures?.map((item) => { 73 return ( 74 <label key={item.prefCode} className="flex mr-14 mt-4"> 75 <input 76 type="checkbox" 77 onChange={(e) => handleChange(e.target.checked, item.prefCode)} 78 /> 79 <span>{item.prefName}</span> 80 </label> 81 ); 82 })} 83 </div> 84 <div className="w-9/12 m-auto mt-28"> 85 <HighchartsReact constructorType={"chart"} options={options} /> 86 </div> 87 </div> 88 ); 89}

コードの解説らしきものを書いておきます。

  • 表示の順番はクリックした順番です。(一度非表示にして再表示すると色が変わるのが気になる…。)
  • 人口データはそんなに変化しないと思うので、一度取ってきたものは非表示でもキャッシュしてます。
  • useEffect を使うと無駄な render が発生するので、なるべく使わないようにしました。
  • useState も必要最小限なものに絞り込みました。
  • graphData のところはループで書いても良いと思います。(その方が分かりやすいかも…。)
  • graphData の data は、配列を作り直さないと表示がおかしくなるので仕方なく再生成してます。
  • Map はキーが number なので使ってみましたが、オブジェクトでも良かったかも。

投稿2021/02/28 17:13

編集2021/03/01 03:36
hoshi-takanori

総合スコア7899

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kAAAAA

2021/02/28 22:25

ありがとうございます。 こちら無事に解決できました。 引数にprefを渡すことで前の値と比較することができるのは初耳でした。
kAAAAA

2021/02/28 22:38

自分が書いたコードで足りないものはやはりJavaScript周りの知識でしょうか? filterで加工したりnew Mapも好んで使ってきませんでした。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問