<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>React アーカイブ - Sheltie Garage Tech</title>
	<atom:link href="https://sheltie-garage.xyz/tech/category/react/feed/" rel="self" type="application/rss+xml" />
	<link>https://sheltie-garage.xyz/tech/category/react/</link>
	<description>テクノロジー関連の話題をまとめたブログです</description>
	<lastBuildDate>Sat, 04 Oct 2025 09:33:25 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>
	<item>
		<title>Next.jsでMetatag(OGPタグ)を返却する</title>
		<link>https://sheltie-garage.xyz/tech/2025/10/next-js%e3%81%a7metatagogp%e3%82%bf%e3%82%b0%e3%82%92%e8%bf%94%e5%8d%b4%e3%81%99%e3%82%8b/</link>
					<comments>https://sheltie-garage.xyz/tech/2025/10/next-js%e3%81%a7metatagogp%e3%82%bf%e3%82%b0%e3%82%92%e8%bf%94%e5%8d%b4%e3%81%99%e3%82%8b/#respond</comments>
		
		<dc:creator><![CDATA[monodon]]></dc:creator>
		<pubDate>Sat, 04 Oct 2025 09:31:04 +0000</pubDate>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[React]]></category>
		<guid isPermaLink="false">https://sheltie-garage.xyz/tech/?p=1273</guid>

					<description><![CDATA[<p>React + Next.jsで作成したアプリ(フロントエンド)からOGPタグを返却したかったので調査したときのメモです OGPタグはなぜ必要？ XServerさんの説明はこちらhttps://www.xserver.n [&#8230;]</p>
<p>投稿 <a href="https://sheltie-garage.xyz/tech/2025/10/next-js%e3%81%a7metatagogp%e3%82%bf%e3%82%b0%e3%82%92%e8%bf%94%e5%8d%b4%e3%81%99%e3%82%8b/">Next.jsでMetatag(OGPタグ)を返却する</a> は <a href="https://sheltie-garage.xyz/tech">Sheltie Garage Tech</a> に最初に表示されました。</p>
]]></description>
										<content:encoded><![CDATA[
<p>React + Next.jsで作成したアプリ(フロントエンド)からOGPタグを返却したかったので調査したときのメモです</p>



<h2 class="wp-block-heading">OGPタグはなぜ必要？</h2>



<p>XServerさんの説明はこちら<br><a href="https://www.xserver.ne.jp/bizhp/open-graph-protocol/" target="_blank" rel="noreferrer noopener">https://www.xserver.ne.jp/bizhp/open-graph-protocol/</a></p>



<p>ざっくりな内容として「SNSなどにリンクをシェアしたときに、タイトルや画像を表示するための仕組み」です<br>今回、趣味開発しているWebアプリに「SNSで投稿内容をシェアするためのURLを発行する」機能を追加するにあたり、X(Twitter)などに画像やタイトルを表示させる必要があったため、OGPタグを追加することにしました。<br>(ちなみに、自分が作成しているサイトはライダー向けツーリングスポット共有サイトで、マップ上にスポットを投稿できるようなWebサイトです)</p>



<p>↓こんな感じで、Xポスト内に投稿した内容が画像付きで表示されるようになります</p>



<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">ヤギ！柵まで近づいてきてくれて可愛かった！<br> <a href="https://t.co/YMV9Hki6hV">https://t.co/YMV9Hki6hV</a> <a href="https://twitter.com/hashtag/ProjectRIDE?src=hash&amp;ref_src=twsrc%5Etfw">#ProjectRIDE</a> <a href="https://twitter.com/hashtag/%E3%83%84%E3%83%BC%E3%83%AA%E3%83%B3%E3%82%B0?src=hash&amp;ref_src=twsrc%5Etfw">#ツーリング</a></p>&mdash; ProjectRIDE (@ProjectRID46883) <a href="https://twitter.com/ProjectRID46883/status/1973176508316524786?ref_src=twsrc%5Etfw">October 1, 2025</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>



<h2 class="wp-block-heading">Next.jsでOGPタグを返却する仕組み</h2>



<p>Next.jsで開発するアプリでOGPタグを返却する場合、以下の2通りの方法が利用できます</p>



<ul class="wp-block-list">
<li>metadataオブジェクトを定義し、固定値を返却</li>



<li>generateMetaData関数を定義し、動的な値を返却</li>
</ul>



<h2 class="wp-block-heading">metadataオブジェクトを使用する場合</h2>



<p>固定ページなど、動的に情報を取得する必要がない場合metadataオブジェクトをlayout.jsやpage.jsに定義してメタデータ(OGPタグなど)を返却することができます<br><a href="https://nextjs.org/docs/app/api-reference/functions/generate-metadata#metadata-fields">https://nextjs.org/docs/app/api-reference/functions/generate-metadata#metadata-</a><a href="https://nextjs.org/docs/app/api-reference/functions/generate-metadata#metadata-fields" target="_blank" rel="noreferrer noopener">fields</a></p>



<p>動的な取得が必要なければ、こちらを利用するのが簡単そうですね!</p>



<h2 class="wp-block-heading">generateMetada関数を使用する場合</h2>



<p>例えば、ユーザーの投稿内容を表示するなど、内容を動的に取得する必要がある場合は「generateMetadata」ファンクションを使用する必要があります<br>https://nextjs.org/docs/app/api-reference/functions/generate-metadata</p>



<p>自分のサイトでは以下の方法で実装しています。実装先はapp/page.tsxになります</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-ts" data-lang="TypeScript"><code>type Props = {
  params: Promise&lt;{ id: string }&gt;
  searchParams: Promise&lt;{ [key: string]: string | string[] | undefined }&gt;
}

// SNSシェアリンク用のOGP生成処理
// https://www.project-ride.com/content_id=1 でアクセスされたときに実行される
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export async function generateMetadata({ params, searchParams }: Props, parent: ResolvingMetadata): Promise&lt;Metadata&gt; {
  
  const resolvedSearchParams = await searchParams
  const contentId = resolvedSearchParams.content_id
  const wwwBaseUrl = process.env.NEXT_PUBLIC_WWW_BASE_URL ?? &quot;&quot;
  const defaultImageUrl = `${process.env.NEXT_PUBLIC_IMAGE_BASE_URL ?? &quot;&quot;}${process.env.NEXT_PUBLIC_NO_IMAGE ?? &quot;&quot;}`  

  // もし content_id が URL にあれば...
  if (typeof contentId === &#39;string&#39;) {
    const content = await getContent(contentId);

    if (content) {
      const imageUrl = content.image_url
        ? (process.env.NEXT_PUBLIC_IMAGE_BASE_URL ?? &quot;&quot;) + content.image_url
        : defaultImageUrl;

      const title = content.message.replace(/&lt;br\s*\/?&gt;/gi, &#39;&#39;).substring(0, 30) + &#39;...&#39;;
      const description = content.message;

      return {
        title: title, // タイトル用にメッセージを短縮
        description: description,
        openGraph: {
          title: title,
          description: description,
          url: `${wwwBaseUrl}?content_id=${contentId}`,
          images: [{ url: imageUrl }],
        },
        twitter: {
          card: &#39;summary_large_image&#39;,
          title: title,
          description: description,
          images: [imageUrl],
        }
      }
    }
  }

  // 有効なコンテンツが見つからない場合、デフォルト内容を返却
  return {
    title: &#39;RIDE-Mono&#39;,
    description: &#39;バイク乗りのためのおすすめスポット共有サイト&#39;,
    openGraph: {
      title: &#39;RIDE-Mono&#39;,
      description: &#39;バイク乗りのためのおすすめスポット共有サイト&#39;,
      url: wwwBaseUrl,
      images: [{ url: &quot;&quot; }], // デフォルト画像
    }
  }
}</code></pre></div>



<p>スクリプト内のgetContent関数でユーザー投稿内容を取得し、メタデータを設定しています</p>



<p class="has-black-color has-text-color has-link-color wp-elements-c63e69e26ea30bb3dfa079b2bff16dd3">注意点としてgenerateMetadata関数は<strong>サーバーコンポーネント</strong>で実行する必要があります<br>自分が最初作成したとき、クライアントコンポーネントにてページを作成していたため、generateMetadata関数を利用するために、既存のページ内容を別途クライアントコンポーネントのファイルに別出しして対応を行いました</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>export default function Home() {
  return (&lt;TopPage /&gt;);
}</code></pre></div>



<p>もともと記載していた内容をTopPageコンポーネントに分離しています<br>TopPageコンポーネントでは、&#8217;use client&#8217;を利用し、クライアントコンポーネントとして動作させています</p>



<h2 class="wp-block-heading">プレビューが出ない時がある</h2>



<p>生成したリンクをX(Twitter)に貼り付けたときにプレビューが表示されたり、されなかったりといった症状がでてデバッグに苦戦しました<br>実際には投稿後に正しくOGPの内容が表示されたので、投稿前のプレビューの精度は参考程度に考えていたほうが良いのかもしれません(逆に投稿したのに、想定したOGPの内容が表示されない場合は、何かを間違えている可能性が高い)</p>



<h2 class="wp-block-heading">以上です</h2>



<p>ということでNext.jsからMetadata(OGPタグ)を返却する方法でした<br>SPAだとどうやってMetadataを返却しているのか正直謎でしたが、調べてみるときちんと仕組みが備わっているんですね！</p>



<p>Metadataを生成することで、SNSシェア以外にもクローラー対応など、色々できることが増えそうです</p>
<p>投稿 <a href="https://sheltie-garage.xyz/tech/2025/10/next-js%e3%81%a7metatagogp%e3%82%bf%e3%82%b0%e3%82%92%e8%bf%94%e5%8d%b4%e3%81%99%e3%82%8b/">Next.jsでMetatag(OGPタグ)を返却する</a> は <a href="https://sheltie-garage.xyz/tech">Sheltie Garage Tech</a> に最初に表示されました。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://sheltie-garage.xyz/tech/2025/10/next-js%e3%81%a7metatagogp%e3%82%bf%e3%82%b0%e3%82%92%e8%bf%94%e5%8d%b4%e3%81%99%e3%82%8b/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>OpenSearchでなにか作るぞ!(その8 フロントサイドを引き続きつくる）</title>
		<link>https://sheltie-garage.xyz/tech/2023/10/opensearch%e3%81%a7%e3%81%aa%e3%81%ab%e3%81%8b%e4%bd%9c%e3%82%8b%e3%81%9e%e3%81%9d%e3%81%ae8-%e3%83%95%e3%83%ad%e3%83%b3%e3%83%88%e3%82%b5%e3%82%a4%e3%83%89%e3%82%92%e5%bc%95%e3%81%8d%e7%b6%9a/</link>
					<comments>https://sheltie-garage.xyz/tech/2023/10/opensearch%e3%81%a7%e3%81%aa%e3%81%ab%e3%81%8b%e4%bd%9c%e3%82%8b%e3%81%9e%e3%81%9d%e3%81%ae8-%e3%83%95%e3%83%ad%e3%83%b3%e3%83%88%e3%82%b5%e3%82%a4%e3%83%89%e3%82%92%e5%bc%95%e3%81%8d%e7%b6%9a/#respond</comments>
		
		<dc:creator><![CDATA[monodon]]></dc:creator>
		<pubDate>Tue, 10 Oct 2023 08:44:30 +0000</pubDate>
				<category><![CDATA[OpenSearch]]></category>
		<category><![CDATA[React]]></category>
		<guid isPermaLink="false">https://sheltie-garage.xyz/tech/?p=897</guid>

					<description><![CDATA[<p>最近あまり作業できていなかったdAnimeSearchプロジェクト。今回はフロントを引き続き作っていきます。 イベントハンドラとダミーデータでモックを作成する 前回まででざっくりとフォルダ構成やコンポーネントの構成を決め [&#8230;]</p>
<p>投稿 <a href="https://sheltie-garage.xyz/tech/2023/10/opensearch%e3%81%a7%e3%81%aa%e3%81%ab%e3%81%8b%e4%bd%9c%e3%82%8b%e3%81%9e%e3%81%9d%e3%81%ae8-%e3%83%95%e3%83%ad%e3%83%b3%e3%83%88%e3%82%b5%e3%82%a4%e3%83%89%e3%82%92%e5%bc%95%e3%81%8d%e7%b6%9a/">OpenSearchでなにか作るぞ!(その8 フロントサイドを引き続きつくる）</a> は <a href="https://sheltie-garage.xyz/tech">Sheltie Garage Tech</a> に最初に表示されました。</p>
]]></description>
										<content:encoded><![CDATA[
<p>最近あまり作業できていなかったdAnimeSearchプロジェクト。<br>今回はフロントを引き続き作っていきます。</p>



<h2 class="wp-block-heading">イベントハンドラとダミーデータでモックを作成する</h2>



<p>前回まででざっくりとフォルダ構成やコンポーネントの構成を決めました。<br>今回はひとまずイベントハンドラとダミーデータを作成して、大まかに動くようにしたいと思います。</p>



<p>前回のおさらいです</p>



<figure class="wp-block-image size-large"><img fetchpriority="high" decoding="async" width="1024" height="587" src="https://sheltie-garage.xyz/tech/wp-content/uploads/2023/10/20231010_001-1024x587.png" alt="" class="wp-image-898" srcset="https://sheltie-garage.xyz/tech/wp-content/uploads/2023/10/20231010_001-1024x587.png 1024w, https://sheltie-garage.xyz/tech/wp-content/uploads/2023/10/20231010_001-300x172.png 300w, https://sheltie-garage.xyz/tech/wp-content/uploads/2023/10/20231010_001-768x440.png 768w, https://sheltie-garage.xyz/tech/wp-content/uploads/2023/10/20231010_001.png 1242w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>・components &#8211; template : 検索条件と検索結果をそれぞれ表示するテンプレート<br>・components &#8211; ui-elements:ボタンやテキストボックスなどの最小単位のコンポーネント<br>・pages:親コンポーネントに位置するコンポーネント。この中でテンプレートを読み込む</p>



<h3 class="wp-block-heading">SearchConditionTemplate.tsxの中身</h3>



<div class="hcb_wrap"><pre class="prism line-numbers lang-ts" data-lang="TypeScript"><code>import SearchButton from &quot;../ui-elements/SearchButton&quot;;
import SearchTextBox from &quot;../ui-elements/SearchTextBox&quot;;

const SearchConditionTemplate = (props : any) =&gt; {
    return(
        &lt;div&gt;
            &lt;SearchTextBox onChange={props.handleKeywordChange} /&gt;&lt;SearchButton onClick={props.onClick}/&gt;
        &lt;/div&gt;
    );
}

export default SearchConditionTemplate;</code></pre></div>



<p>こんな感じで、テキストボックスと検索用ボタンのみとなります。<br>各イベントハンドラは親コンポーネントからプロパティ経由で取得します。</p>



<h3 class="wp-block-heading">SearchResultTemplate.tsxの中身</h3>



<div class="hcb_wrap"><pre class="prism line-numbers lang-ts" data-lang="TypeScript"><code>import SearchResultCard from &quot;../ui-elements/SearchResultCard&quot;;

const SearchResultTemplate = (searchResultProps: any) =&gt; {

    let list = [];

    if(searchResultProps == null){
        return ;
    }

    for(const [i, result] of searchResultProps.results.entries()){
        list.push(&lt;SearchResultCard result/&gt;);
    }

    return(
        &lt;div&gt;
            {list}
        &lt;/div&gt;
    );
}

export default SearchResultTemplate;</code></pre></div>



<p>検索結果を表示するだけのページになります。プロパティ経由で検索結果を受け取り、画面に表示します。</p>



<h3 class="wp-block-heading">search.tsxの中身</h3>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>import { SetStateAction, useState } from &quot;react&quot;;
import SearchConditionTemplate from &quot;@/components/template/SearchConditionTemplate&quot;;
import SearchResultTemplate from &quot;@/components/template/SearchResultTemplate&quot;;


const Search = () =&gt; {

    // ステートの宣言
    const [keyword, setKeyword] = useState(&#39;&#39;);
    const [searchResults, setSearchResults] = useState&lt;any[]&gt;([]);

    // 入力値変更イベントハンドラ
    const handleKeywordChange = (e : any) =&gt; {
        console.log(&quot;キーワード変更&quot;);
        setKeyword(e.target.value);
      };

    // 検索イベントハンドラ
    const handleSearch = () =&gt; {
        console.log(&quot;検索クリック&quot;);
        // ここで実際の検索処理を実装する
        // 例: ダミーの検索結果を設定
        const dummyResults = [
          { id: 1, title: &#39;検索結果1&#39; },
          { id: 2, title: &#39;検索結果2&#39; },
          { id: 3, title: &#39;検索結果3&#39; },
        ];
        setSearchResults(dummyResults);
      };

    return(
        &lt;div className=&quot;App&quot;&gt;
            &lt;SearchConditionTemplate handleKeywordChange={handleKeywordChange} onClick={handleSearch}/&gt;
            &lt;SearchResultTemplate results={searchResults}/&gt;
        &lt;/div&gt;
    );
}

export default Search</code></pre></div>



<p>親コンポーネントとなるsearchコンポーネントの中身。<br>各テンプレートを読み込んで表示を行うことと、イベントハンドラやステートを宣言し、各コンポーネントへプロパティ経由で受け渡します。</p>



<p>検索結果は今のところダミーデータですが、将来的に検索ボタンをクリックしたときにOpenSearchに検索を行い、結果を受け渡すように変更します。</p>



<h2 class="wp-block-heading">ここまでの動き</h2>



<p>ここまで作成すると、以下のような画面になります。</p>



<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="472" src="https://sheltie-garage.xyz/tech/wp-content/uploads/2023/10/20231010_002-1024x472.png" alt="" class="wp-image-899" srcset="https://sheltie-garage.xyz/tech/wp-content/uploads/2023/10/20231010_002-1024x472.png 1024w, https://sheltie-garage.xyz/tech/wp-content/uploads/2023/10/20231010_002-300x138.png 300w, https://sheltie-garage.xyz/tech/wp-content/uploads/2023/10/20231010_002-768x354.png 768w, https://sheltie-garage.xyz/tech/wp-content/uploads/2023/10/20231010_002.png 1503w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>見た目がかなりしょぼい上に、実行時エラーも発生してしまっていますが、良いのです。<br>このあたりの不具合はこの後修正します。</p>



<h2 class="wp-block-heading">今回はここまで</h2>



<p>ということで、本日はここまで。<br>進みは遅いですが、趣味で作っているものなのでご勘弁を。<br>毎週少しでも開発を続けていれば、いつかは完成する精神なので長い目でお付き合いいただけたらと思います。</p>


<div id="rinkerid863" class="yyi-rinker-contents  yyi-rinker-postid-863 yyi-rinker-img-m yyi-rinker-catid-18 yyi-rinker-catid-8 ">
	<div class="yyi-rinker-box">
		<div class="yyi-rinker-image">
							<a href="https://af.moshimo.com/af/c/click?a_id=3394378&#038;p_id=54&#038;pc_id=54&#038;pl_id=616&#038;url=https%3A%2F%2Fsearch.rakuten.co.jp%2Fsearch%2Fmall%2Freact%2F%3Ff%3D1%26grp%3Dproduct" rel="nofollow"><img decoding="async" src="https://thumbnail.image.rakuten.co.jp/@0_mall/book/cabinet/9163/9784297129163_1_4.jpg?_ex=128x128" width="128" height="128" class="yyi-rinker-main-img" style="border: none;" loading="lazy"></a><img decoding="async" src="https://i.moshimo.com/af/i/impression?a_id=3394378&amp;p_id=54&amp;pc_id=54&amp;pl_id=616" width="1" height="1" style="border:none;">					</div>
		<div class="yyi-rinker-info">
			<div class="yyi-rinker-title">
									<a href="https://af.moshimo.com/af/c/click?a_id=3394378&#038;p_id=54&#038;pc_id=54&#038;pl_id=616&#038;url=https%3A%2F%2Fsearch.rakuten.co.jp%2Fsearch%2Fmall%2Freact%2F%3Ff%3D1%26grp%3Dproduct" rel="nofollow">TypeScriptとReact/Next.jsでつくる実践Webアプリケーション開発 [ 手島 拓也 ]</a><img decoding="async" src="https://i.moshimo.com/af/i/impression?a_id=3394378&amp;p_id=54&amp;pc_id=54&amp;pl_id=616" width="1" height="1" style="border:none;">							</div>
			<div class="yyi-rinker-detail">
							<div class="credit-box">created by&nbsp;<a href="https://oyakosodate.com/rinker/" rel="nofollow noopener" target="_blank" >Rinker</a></div>
										<div class="price-box">
							<span title="" class="price">¥3,498</span>
															<span class="price_at">(2026/04/30 15:35:44時点&nbsp;楽天市場調べ-</span><span title="このサイトで掲載されている情報は当サイトの作成者により運営されています。価格、販売可能情報は、変更される場合があります。購入時に楽天市場店舗（www.rakuten.co.jp）に表示されている価格がその商品の販売に適用されます。">詳細)</span>
																	</div>
						</div>
						<ul class="yyi-rinker-links">
																                    <li class="amazonlink">
						<a href="https://www.amazon.co.jp/gp/search?ie=UTF8&amp;keywords=react&amp;tag=monodon-22&amp;index=blended&amp;linkCode=ure&amp;creative=6339" rel="nofollow" class="yyi-rinker-link">Amazon</a>					</li>
													<li class="rakutenlink">
						<a href="https://af.moshimo.com/af/c/click?a_id=3394378&amp;p_id=54&amp;pc_id=54&amp;pl_id=616&amp;url=https%3A%2F%2Fsearch.rakuten.co.jp%2Fsearch%2Fmall%2Freact%2F%3Ff%3D1%26grp%3Dproduct" rel="nofollow" class="yyi-rinker-link">楽天市場</a><img decoding="async" src="https://i.moshimo.com/af/i/impression?a_id=3394378&amp;p_id=54&amp;pc_id=54&amp;pl_id=616" width="1" height="1" style="border:none;">					</li>
													<li class="yahoolink">
						<a href="https://af.moshimo.com/af/c/click?a_id=3442618&amp;p_id=1225&amp;pc_id=1925&amp;pl_id=18502&amp;url=https%3A%2F%2Fshopping.yahoo.co.jp%2Fsearch%3Fp%3Dreact" rel="nofollow" class="yyi-rinker-link">Yahooショッピング</a><img loading="lazy" decoding="async" src="https://i.moshimo.com/af/i/impression?a_id=3442618&amp;p_id=1225&amp;pc_id=1925&amp;pl_id=18502" width="1" height="1" style="border:none;">					</li>
				                											</ul>
					</div>
	</div>
</div>


<div id="rinkerid645" class="yyi-rinker-contents  yyi-rinker-postid-645 yyi-rinker-img-m yyi-rinker-catid-18 yyi-rinker-catid-8 ">
	<div class="yyi-rinker-box">
		<div class="yyi-rinker-image">
							<a href="https://af.moshimo.com/af/c/click?a_id=3394378&#038;p_id=54&#038;pc_id=54&#038;pl_id=616&#038;url=https%3A%2F%2Fsearch.rakuten.co.jp%2Fsearch%2Fmall%2FGo%25E8%25A8%2580%25E8%25AA%259E%2F%3Ff%3D1%26grp%3Dproduct" rel="nofollow"><img decoding="async" src="https://thumbnail.image.rakuten.co.jp/@0_mall/book/cabinet/9694/9784873119694_1_3.jpg?_ex=128x128" width="128" height="128" class="yyi-rinker-main-img" style="border: none;" loading="lazy"></a><img decoding="async" src="https://i.moshimo.com/af/i/impression?a_id=3394378&amp;p_id=54&amp;pc_id=54&amp;pl_id=616" width="1" height="1" style="border:none;">					</div>
		<div class="yyi-rinker-info">
			<div class="yyi-rinker-title">
									<a href="https://af.moshimo.com/af/c/click?a_id=3394378&#038;p_id=54&#038;pc_id=54&#038;pl_id=616&#038;url=https%3A%2F%2Fsearch.rakuten.co.jp%2Fsearch%2Fmall%2FGo%25E8%25A8%2580%25E8%25AA%259E%2F%3Ff%3D1%26grp%3Dproduct" rel="nofollow">実用 Go言語 システム開発の現場で知っておきたいアドバイス [ 渋川 よしき ]</a><img decoding="async" src="https://i.moshimo.com/af/i/impression?a_id=3394378&amp;p_id=54&amp;pc_id=54&amp;pl_id=616" width="1" height="1" style="border:none;">							</div>
			<div class="yyi-rinker-detail">
							<div class="credit-box">created by&nbsp;<a href="https://oyakosodate.com/rinker/" rel="nofollow noopener" target="_blank" >Rinker</a></div>
										<div class="price-box">
							<span title="" class="price">¥3,960</span>
															<span class="price_at">(2026/04/30 06:22:26時点&nbsp;楽天市場調べ-</span><span title="このサイトで掲載されている情報は当サイトの作成者により運営されています。価格、販売可能情報は、変更される場合があります。購入時に楽天市場店舗（www.rakuten.co.jp）に表示されている価格がその商品の販売に適用されます。">詳細)</span>
																	</div>
						</div>
						<ul class="yyi-rinker-links">
																                    <li class="amazonlink">
						<a href="https://www.amazon.co.jp/gp/search?ie=UTF8&amp;keywords=Go%E8%A8%80%E8%AA%9E&amp;tag=monodon-22&amp;index=blended&amp;linkCode=ure&amp;creative=6339" rel="nofollow" class="yyi-rinker-link">Amazon</a>					</li>
													<li class="rakutenlink">
						<a href="https://af.moshimo.com/af/c/click?a_id=3394378&amp;p_id=54&amp;pc_id=54&amp;pl_id=616&amp;url=https%3A%2F%2Fsearch.rakuten.co.jp%2Fsearch%2Fmall%2FGo%25E8%25A8%2580%25E8%25AA%259E%2F%3Ff%3D1%26grp%3Dproduct" rel="nofollow" class="yyi-rinker-link">楽天市場</a><img decoding="async" src="https://i.moshimo.com/af/i/impression?a_id=3394378&amp;p_id=54&amp;pc_id=54&amp;pl_id=616" width="1" height="1" style="border:none;">					</li>
													<li class="yahoolink">
						<a href="https://af.moshimo.com/af/c/click?a_id=3442618&amp;p_id=1225&amp;pc_id=1925&amp;pl_id=18502&amp;url=https%3A%2F%2Fshopping.yahoo.co.jp%2Fsearch%3Fp%3DGo%25E8%25A8%2580%25E8%25AA%259E" rel="nofollow" class="yyi-rinker-link">Yahooショッピング</a><img loading="lazy" decoding="async" src="https://i.moshimo.com/af/i/impression?a_id=3442618&amp;p_id=1225&amp;pc_id=1925&amp;pl_id=18502" width="1" height="1" style="border:none;">					</li>
				                											</ul>
					</div>
	</div>
</div>
<p>投稿 <a href="https://sheltie-garage.xyz/tech/2023/10/opensearch%e3%81%a7%e3%81%aa%e3%81%ab%e3%81%8b%e4%bd%9c%e3%82%8b%e3%81%9e%e3%81%9d%e3%81%ae8-%e3%83%95%e3%83%ad%e3%83%b3%e3%83%88%e3%82%b5%e3%82%a4%e3%83%89%e3%82%92%e5%bc%95%e3%81%8d%e7%b6%9a/">OpenSearchでなにか作るぞ!(その8 フロントサイドを引き続きつくる）</a> は <a href="https://sheltie-garage.xyz/tech">Sheltie Garage Tech</a> に最初に表示されました。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://sheltie-garage.xyz/tech/2023/10/opensearch%e3%81%a7%e3%81%aa%e3%81%ab%e3%81%8b%e4%bd%9c%e3%82%8b%e3%81%9e%e3%81%9d%e3%81%ae8-%e3%83%95%e3%83%ad%e3%83%b3%e3%83%88%e3%82%b5%e3%82%a4%e3%83%89%e3%82%92%e5%bc%95%e3%81%8d%e7%b6%9a/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>OpenSearchでなにか作るぞ!(その7 フロントサイドを作り始める）</title>
		<link>https://sheltie-garage.xyz/tech/2023/09/opensearch%e3%81%a7%e3%81%aa%e3%81%ab%e3%81%8b%e4%bd%9c%e3%82%8b%e3%81%9e%e3%81%9d%e3%81%ae7-%e3%83%95%e3%83%ad%e3%83%b3%e3%83%88%e3%82%b5%e3%82%a4%e3%83%89%e3%82%92%e4%bd%9c%e3%82%8a%e5%a7%8b/</link>
					<comments>https://sheltie-garage.xyz/tech/2023/09/opensearch%e3%81%a7%e3%81%aa%e3%81%ab%e3%81%8b%e4%bd%9c%e3%82%8b%e3%81%9e%e3%81%9d%e3%81%ae7-%e3%83%95%e3%83%ad%e3%83%b3%e3%83%88%e3%82%b5%e3%82%a4%e3%83%89%e3%82%92%e4%bd%9c%e3%82%8a%e5%a7%8b/#respond</comments>
		
		<dc:creator><![CDATA[monodon]]></dc:creator>
		<pubDate>Mon, 18 Sep 2023 07:58:17 +0000</pubDate>
				<category><![CDATA[React]]></category>
		<guid isPermaLink="false">https://sheltie-garage.xyz/tech/?p=861</guid>

					<description><![CDATA[<p>前回まででサーバーサイド側に検索機能の実装まで終わっているため、今回からフロントエンドを作っていきます。今回は、ざっくりコンポーネントの作成まで行います。 Nextjs + Material UIの組み合わせで行きます  [&#8230;]</p>
<p>投稿 <a href="https://sheltie-garage.xyz/tech/2023/09/opensearch%e3%81%a7%e3%81%aa%e3%81%ab%e3%81%8b%e4%bd%9c%e3%82%8b%e3%81%9e%e3%81%9d%e3%81%ae7-%e3%83%95%e3%83%ad%e3%83%b3%e3%83%88%e3%82%b5%e3%82%a4%e3%83%89%e3%82%92%e4%bd%9c%e3%82%8a%e5%a7%8b/">OpenSearchでなにか作るぞ!(その7 フロントサイドを作り始める）</a> は <a href="https://sheltie-garage.xyz/tech">Sheltie Garage Tech</a> に最初に表示されました。</p>
]]></description>
										<content:encoded><![CDATA[
<p>前回まででサーバーサイド側に検索機能の実装まで終わっているため、今回からフロントエンドを作っていきます。<br>今回は、ざっくりコンポーネントの作成まで行います。</p>



<h2 class="wp-block-heading">Nextjs + Material UIの組み合わせで行きます</h2>



<p>フロントで利用するフレームワークは脳死的にNextjsを選択するのが、最近のマイブームです<br><a href="https://nextjs.org/">https://nextjs.org/</a></p>



<p>GUIはMaterial UIを利用します。こちらも特に理由はなく、完全に好みの問題です。<br><a href="https://mui.com/">https://mui.com/</a></p>



<h2 class="wp-block-heading">Atomic Design的な考えを取り入れつつ、かなり簡素なディレクトリ構成にしました</h2>



<p>ReactでUI設計を行う時は「Atomic Design」を利用することが多いと思います。本プロジェクトでもこの考え方を利用しますが、現状のアプリ内容に合うように少しカスタマイズして利用します。</p>



<p>というのも、今回作成するアプリはとても小さいもので、想定している機能としては<br>・画面から検索を行う<br>・検索結果を表示する<br>程度のものになります。</p>



<p>そのため、ディレクトリについても以下の画像のように<br>・ui-elements:画面の部品となるコンポーネント<br>・template:ui-componentsを組み合わせたページ<br>の2ディレクトリのみとしました。</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="514" src="https://sheltie-garage.xyz/tech/wp-content/uploads/2023/09/20230918_001-1-1024x514.png" alt="" class="wp-image-862" srcset="https://sheltie-garage.xyz/tech/wp-content/uploads/2023/09/20230918_001-1-1024x514.png 1024w, https://sheltie-garage.xyz/tech/wp-content/uploads/2023/09/20230918_001-1-300x150.png 300w, https://sheltie-garage.xyz/tech/wp-content/uploads/2023/09/20230918_001-1-768x385.png 768w, https://sheltie-garage.xyz/tech/wp-content/uploads/2023/09/20230918_001-1-1536x770.png 1536w, https://sheltie-garage.xyz/tech/wp-content/uploads/2023/09/20230918_001-1.png 1958w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<h2 class="wp-block-heading">一旦ここまで</h2>



<p>ということで、こんな感じで作っていますということで、一旦ここまでになります。<br>各コンポーネントはビジネスロジックは持たず、最終的にnextjsのpageディレクトリに配置するページ内に処理に必要なすべてのメソッドを作成し、プロパティ経由で各コンポーネントに受け渡すような設計で進めていきます。</p>



<p>フロントエンド周りは自分が苦手とするところなので、サーバーサイド以上に作成に苦戦しそうですが、なんとか作っていきたいと思います。</p>


<div id="rinkerid863" class="yyi-rinker-contents  yyi-rinker-postid-863 yyi-rinker-img-m yyi-rinker-catid-8 ">
	<div class="yyi-rinker-box">
		<div class="yyi-rinker-image">
							<a href="https://af.moshimo.com/af/c/click?a_id=3394378&#038;p_id=54&#038;pc_id=54&#038;pl_id=616&#038;url=https%3A%2F%2Fsearch.rakuten.co.jp%2Fsearch%2Fmall%2Freact%2F%3Ff%3D1%26grp%3Dproduct" rel="nofollow"><img decoding="async" src="https://thumbnail.image.rakuten.co.jp/@0_mall/book/cabinet/9163/9784297129163_1_4.jpg?_ex=128x128" width="128" height="128" class="yyi-rinker-main-img" style="border: none;" loading="lazy"></a><img loading="lazy" decoding="async" src="https://i.moshimo.com/af/i/impression?a_id=3394378&amp;p_id=54&amp;pc_id=54&amp;pl_id=616" width="1" height="1" style="border:none;">					</div>
		<div class="yyi-rinker-info">
			<div class="yyi-rinker-title">
									<a href="https://af.moshimo.com/af/c/click?a_id=3394378&#038;p_id=54&#038;pc_id=54&#038;pl_id=616&#038;url=https%3A%2F%2Fsearch.rakuten.co.jp%2Fsearch%2Fmall%2Freact%2F%3Ff%3D1%26grp%3Dproduct" rel="nofollow">TypeScriptとReact/Next.jsでつくる実践Webアプリケーション開発 [ 手島 拓也 ]</a><img loading="lazy" decoding="async" src="https://i.moshimo.com/af/i/impression?a_id=3394378&amp;p_id=54&amp;pc_id=54&amp;pl_id=616" width="1" height="1" style="border:none;">							</div>
			<div class="yyi-rinker-detail">
							<div class="credit-box">created by&nbsp;<a href="https://oyakosodate.com/rinker/" rel="nofollow noopener" target="_blank" >Rinker</a></div>
										<div class="price-box">
							<span title="" class="price">¥3,498</span>
															<span class="price_at">(2026/04/30 15:35:44時点&nbsp;楽天市場調べ-</span><span title="このサイトで掲載されている情報は当サイトの作成者により運営されています。価格、販売可能情報は、変更される場合があります。購入時に楽天市場店舗（www.rakuten.co.jp）に表示されている価格がその商品の販売に適用されます。">詳細)</span>
																	</div>
						</div>
						<ul class="yyi-rinker-links">
																                    <li class="amazonlink">
						<a href="https://www.amazon.co.jp/gp/search?ie=UTF8&amp;keywords=react&amp;tag=monodon-22&amp;index=blended&amp;linkCode=ure&amp;creative=6339" rel="nofollow" class="yyi-rinker-link">Amazon</a>					</li>
													<li class="rakutenlink">
						<a href="https://af.moshimo.com/af/c/click?a_id=3394378&amp;p_id=54&amp;pc_id=54&amp;pl_id=616&amp;url=https%3A%2F%2Fsearch.rakuten.co.jp%2Fsearch%2Fmall%2Freact%2F%3Ff%3D1%26grp%3Dproduct" rel="nofollow" class="yyi-rinker-link">楽天市場</a><img loading="lazy" decoding="async" src="https://i.moshimo.com/af/i/impression?a_id=3394378&amp;p_id=54&amp;pc_id=54&amp;pl_id=616" width="1" height="1" style="border:none;">					</li>
													<li class="yahoolink">
						<a href="https://af.moshimo.com/af/c/click?a_id=3442618&amp;p_id=1225&amp;pc_id=1925&amp;pl_id=18502&amp;url=https%3A%2F%2Fshopping.yahoo.co.jp%2Fsearch%3Fp%3Dreact" rel="nofollow" class="yyi-rinker-link">Yahooショッピング</a><img loading="lazy" decoding="async" src="https://i.moshimo.com/af/i/impression?a_id=3442618&amp;p_id=1225&amp;pc_id=1925&amp;pl_id=18502" width="1" height="1" style="border:none;">					</li>
				                											</ul>
					</div>
	</div>
</div>


<div id="rinkerid864" class="yyi-rinker-contents  yyi-rinker-postid-864 yyi-rinker-img-m yyi-rinker-catid-8 ">
	<div class="yyi-rinker-box">
		<div class="yyi-rinker-image">
							<a href="https://af.moshimo.com/af/c/click?a_id=3394378&#038;p_id=54&#038;pc_id=54&#038;pl_id=616&#038;url=https%3A%2F%2Fsearch.rakuten.co.jp%2Fsearch%2Fmall%2FGo%25E8%25A8%2580%25E8%25AA%259E%2F%3Ff%3D1%26grp%3Dproduct" rel="nofollow"><img decoding="async" src="https://thumbnail.image.rakuten.co.jp/@0_mall/book/cabinet/9694/9784873119694_1_3.jpg?_ex=128x128" width="128" height="128" class="yyi-rinker-main-img" style="border: none;" loading="lazy"></a><img loading="lazy" decoding="async" src="https://i.moshimo.com/af/i/impression?a_id=3394378&amp;p_id=54&amp;pc_id=54&amp;pl_id=616" width="1" height="1" style="border:none;">					</div>
		<div class="yyi-rinker-info">
			<div class="yyi-rinker-title">
									<a href="https://af.moshimo.com/af/c/click?a_id=3394378&#038;p_id=54&#038;pc_id=54&#038;pl_id=616&#038;url=https%3A%2F%2Fsearch.rakuten.co.jp%2Fsearch%2Fmall%2FGo%25E8%25A8%2580%25E8%25AA%259E%2F%3Ff%3D1%26grp%3Dproduct" rel="nofollow">実用 Go言語 システム開発の現場で知っておきたいアドバイス [ 渋川 よしき ]</a><img loading="lazy" decoding="async" src="https://i.moshimo.com/af/i/impression?a_id=3394378&amp;p_id=54&amp;pc_id=54&amp;pl_id=616" width="1" height="1" style="border:none;">							</div>
			<div class="yyi-rinker-detail">
							<div class="credit-box">created by&nbsp;<a href="https://oyakosodate.com/rinker/" rel="nofollow noopener" target="_blank" >Rinker</a></div>
										<div class="price-box">
							<span title="" class="price">¥3,960</span>
															<span class="price_at">(2026/04/30 15:35:44時点&nbsp;楽天市場調べ-</span><span title="このサイトで掲載されている情報は当サイトの作成者により運営されています。価格、販売可能情報は、変更される場合があります。購入時に楽天市場店舗（www.rakuten.co.jp）に表示されている価格がその商品の販売に適用されます。">詳細)</span>
																	</div>
						</div>
						<ul class="yyi-rinker-links">
																                    <li class="amazonlink">
						<a href="https://www.amazon.co.jp/gp/search?ie=UTF8&amp;keywords=Go%E8%A8%80%E8%AA%9E&amp;tag=monodon-22&amp;index=blended&amp;linkCode=ure&amp;creative=6339" rel="nofollow" class="yyi-rinker-link">Amazon</a>					</li>
													<li class="rakutenlink">
						<a href="https://af.moshimo.com/af/c/click?a_id=3394378&amp;p_id=54&amp;pc_id=54&amp;pl_id=616&amp;url=https%3A%2F%2Fsearch.rakuten.co.jp%2Fsearch%2Fmall%2FGo%25E8%25A8%2580%25E8%25AA%259E%2F%3Ff%3D1%26grp%3Dproduct" rel="nofollow" class="yyi-rinker-link">楽天市場</a><img loading="lazy" decoding="async" src="https://i.moshimo.com/af/i/impression?a_id=3394378&amp;p_id=54&amp;pc_id=54&amp;pl_id=616" width="1" height="1" style="border:none;">					</li>
													<li class="yahoolink">
						<a href="https://af.moshimo.com/af/c/click?a_id=3442618&amp;p_id=1225&amp;pc_id=1925&amp;pl_id=18502&amp;url=https%3A%2F%2Fshopping.yahoo.co.jp%2Fsearch%3Fp%3DGo%25E8%25A8%2580%25E8%25AA%259E" rel="nofollow" class="yyi-rinker-link">Yahooショッピング</a><img loading="lazy" decoding="async" src="https://i.moshimo.com/af/i/impression?a_id=3442618&amp;p_id=1225&amp;pc_id=1925&amp;pl_id=18502" width="1" height="1" style="border:none;">					</li>
				                											</ul>
					</div>
	</div>
</div>
<p>投稿 <a href="https://sheltie-garage.xyz/tech/2023/09/opensearch%e3%81%a7%e3%81%aa%e3%81%ab%e3%81%8b%e4%bd%9c%e3%82%8b%e3%81%9e%e3%81%9d%e3%81%ae7-%e3%83%95%e3%83%ad%e3%83%b3%e3%83%88%e3%82%b5%e3%82%a4%e3%83%89%e3%82%92%e4%bd%9c%e3%82%8a%e5%a7%8b/">OpenSearchでなにか作るぞ!(その7 フロントサイドを作り始める）</a> は <a href="https://sheltie-garage.xyz/tech">Sheltie Garage Tech</a> に最初に表示されました。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://sheltie-garage.xyz/tech/2023/09/opensearch%e3%81%a7%e3%81%aa%e3%81%ab%e3%81%8b%e4%bd%9c%e3%82%8b%e3%81%9e%e3%81%9d%e3%81%ae7-%e3%83%95%e3%83%ad%e3%83%b3%e3%83%88%e3%82%b5%e3%82%a4%e3%83%89%e3%82%92%e4%bd%9c%e3%82%8a%e5%a7%8b/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Reactを利用したWebアプリでCookieがなかなかできずにハマった話</title>
		<link>https://sheltie-garage.xyz/tech/2023/07/cookie%e3%81%8c%e3%81%aa%e3%81%8b%e3%81%aa%e3%81%8b%e3%81%a7%e3%81%8d%e3%81%9a%e3%81%ab%e3%83%8f%e3%83%9e%e3%81%a3%e3%81%9f%e8%a9%b1/</link>
					<comments>https://sheltie-garage.xyz/tech/2023/07/cookie%e3%81%8c%e3%81%aa%e3%81%8b%e3%81%aa%e3%81%8b%e3%81%a7%e3%81%8d%e3%81%9a%e3%81%ab%e3%83%8f%e3%83%9e%e3%81%a3%e3%81%9f%e8%a9%b1/#respond</comments>
		
		<dc:creator><![CDATA[monodon]]></dc:creator>
		<pubDate>Mon, 17 Jul 2023 02:13:27 +0000</pubDate>
				<category><![CDATA[Go]]></category>
		<category><![CDATA[React]]></category>
		<guid isPermaLink="false">https://sheltie-garage.xyz/tech/?p=785</guid>

					<description><![CDATA[<p>もちろん、料理の話ではなくて、ブラウザに保存されているCookieの話です 概要 現在個人で作成しているWebアプリでログイン周りの実装を行っていました。開発の環境としては、・フロントサイド：Reactのlocalhos [&#8230;]</p>
<p>投稿 <a href="https://sheltie-garage.xyz/tech/2023/07/cookie%e3%81%8c%e3%81%aa%e3%81%8b%e3%81%aa%e3%81%8b%e3%81%a7%e3%81%8d%e3%81%9a%e3%81%ab%e3%83%8f%e3%83%9e%e3%81%a3%e3%81%9f%e8%a9%b1/">Reactを利用したWebアプリでCookieがなかなかできずにハマった話</a> は <a href="https://sheltie-garage.xyz/tech">Sheltie Garage Tech</a> に最初に表示されました。</p>
]]></description>
										<content:encoded><![CDATA[
<p>もちろん、料理の話ではなくて、ブラウザに保存されているCookieの話です</p>



<h2 class="wp-block-heading">概要</h2>



<p>現在個人で作成しているWebアプリでログイン周りの実装を行っていました。<br>開発の環境としては、<br>・フロントサイド：Reactのlocalhost:3000<br>・バックサイド：Goのlocalhost:1323<br>というCORS状態で開発しています。</p>



<p>ログイン認証方式は昔ながらの「ログイン、パスワードを入力してログインを行い、セッションIDをCookieに保存する」方式です。</p>



<h2 class="wp-block-heading">結論：GoとReactを以下のように修正</h2>



<p>Go側の変更</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>	e.Use(middleware.CORSWithConfig(middleware.CORSConfig{
		AllowOrigins:     []string{&quot;http://localhost:3000&quot;},
		AllowHeaders:     []string{echo.HeaderOrigin, echo.HeaderContentType, echo.HeaderAccept},
		AllowCredentials: true, // ←これを追加
	}))</code></pre></div>



<p>React側(axios)の変更</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>    axios.get(&#39;http://localhost:1323/&#39;, 
      { withCredentials: true }) // ← これを追加
      .then(res =&gt; { 
      console.log(res.data)
    });</code></pre></div>



<p>以上でCookieが保存できるようになりました。これにたどり着くまでに12時間くらいかかった・・・</p>



<p>ヒントにしたのは以下のサイトです。<br>https://stackoverflow.com/questions/72612730/browser-is-not-saving-cookie<br>https://stackoverflow.com/questions/43002444/make-axios-send-cookies-in-its-requests-automatically</p>



<p>Go側の設定は無くてもCookieが保存できましたが、以下のようなエラーが発生したため加えています。</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="122" src="https://sheltie-garage.xyz/tech/wp-content/uploads/2023/07/20230717_010-1024x122.png" alt="" class="wp-image-807" srcset="https://sheltie-garage.xyz/tech/wp-content/uploads/2023/07/20230717_010-1024x122.png 1024w, https://sheltie-garage.xyz/tech/wp-content/uploads/2023/07/20230717_010-300x36.png 300w, https://sheltie-garage.xyz/tech/wp-content/uploads/2023/07/20230717_010-768x91.png 768w, https://sheltie-garage.xyz/tech/wp-content/uploads/2023/07/20230717_010.png 1260w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>以上！</p>



<p>以下、現象について</p>



<h2 class="wp-block-heading">Cookieがどう頑張っても保存されない</h2>



<p>Go + Echoでサーバーサイドを作成していますが、Cookieがどうやっても保存できずハマっていました。<br>クライアントサイドはReact(Nextjs)です。<br>EchoのCookieの利用方法は<a href="https://echo.labstack.com/docs/cookies" target="_blank" rel="noreferrer noopener">こちら</a>になります。</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="241" src="https://sheltie-garage.xyz/tech/wp-content/uploads/2023/07/20230716_001-1024x241.png" alt="" class="wp-image-786" srcset="https://sheltie-garage.xyz/tech/wp-content/uploads/2023/07/20230716_001-1024x241.png 1024w, https://sheltie-garage.xyz/tech/wp-content/uploads/2023/07/20230716_001-300x71.png 300w, https://sheltie-garage.xyz/tech/wp-content/uploads/2023/07/20230716_001-768x181.png 768w, https://sheltie-garage.xyz/tech/wp-content/uploads/2023/07/20230716_001-1536x362.png 1536w, https://sheltie-garage.xyz/tech/wp-content/uploads/2023/07/20230716_001.png 1915w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="346" src="https://sheltie-garage.xyz/tech/wp-content/uploads/2023/07/20230716_002-1024x346.png" alt="" class="wp-image-787" srcset="https://sheltie-garage.xyz/tech/wp-content/uploads/2023/07/20230716_002-1024x346.png 1024w, https://sheltie-garage.xyz/tech/wp-content/uploads/2023/07/20230716_002-300x101.png 300w, https://sheltie-garage.xyz/tech/wp-content/uploads/2023/07/20230716_002-768x259.png 768w, https://sheltie-garage.xyz/tech/wp-content/uploads/2023/07/20230716_002.png 1046w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>Cookieのレスポンスは返却されており、有効期間も未来日に設定しているのになぜ？という状態でした。</p>



<p>更におかしいのが「EditThisCookie」の拡張機能からもCookieが作成できないという点。<br>この場合、自分のプログラムの組み方とは別の場所に問題がありそうな気がします。</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="573" height="609" src="https://sheltie-garage.xyz/tech/wp-content/uploads/2023/07/20230716_003.png" alt="" class="wp-image-789" srcset="https://sheltie-garage.xyz/tech/wp-content/uploads/2023/07/20230716_003.png 573w, https://sheltie-garage.xyz/tech/wp-content/uploads/2023/07/20230716_003-282x300.png 282w" sizes="auto, (max-width: 573px) 100vw, 573px" /></figure>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="567" height="210" src="https://sheltie-garage.xyz/tech/wp-content/uploads/2023/07/20230716_004.png" alt="" class="wp-image-790" srcset="https://sheltie-garage.xyz/tech/wp-content/uploads/2023/07/20230716_004.png 567w, https://sheltie-garage.xyz/tech/wp-content/uploads/2023/07/20230716_004-300x111.png 300w" sizes="auto, (max-width: 567px) 100vw, 567px" /></figure>



<h2 class="wp-block-heading">問題の切り分け</h2>



<p>試しにReactを経由せず、GoのAPIを直接叩いてみたところ無事にCookieが保存されることを確認。</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="672" src="https://sheltie-garage.xyz/tech/wp-content/uploads/2023/07/20230717_011-1024x672.png" alt="" class="wp-image-808" srcset="https://sheltie-garage.xyz/tech/wp-content/uploads/2023/07/20230717_011-1024x672.png 1024w, https://sheltie-garage.xyz/tech/wp-content/uploads/2023/07/20230717_011-300x197.png 300w, https://sheltie-garage.xyz/tech/wp-content/uploads/2023/07/20230717_011-768x504.png 768w, https://sheltie-garage.xyz/tech/wp-content/uploads/2023/07/20230717_011.png 1332w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>ということで、React経由でアクセスすると上手く行かないことが分かり、そちらの方面で調べてみることにしました。</p>



<p>「react acookie not saved」などと検索して、冒頭で紹介したサイトに行き着いて解決しました。</p>



<h2 class="wp-block-heading">今更ながらCookie周りについて確認</h2>



<p><a href="https://developer.mozilla.org/ja/docs/Web/API/XMLHttpRequest/withCredentials">https://developer.mozilla.org/ja/docs/Web/API/XMLHttpRequest/withCredentials</a></p>



<p><a href="https://qiita.com/kawaz/items/1e51c374b7a13c21b7e2">https://qiita.com/kawaz/items/1e51c374b7a13c21b7e2</a></p>



<p>CORSの環境では上記の設定が必要とのこと・・・<br>今までCORSの環境でいくつか個人アプリは作っていましたが、実はCookieを利用するのは今回が初めてというところもあり、予定外のところで詰まってしまいました・・・</p>



<p>アプリが完成した場合、本番環境でもCORSの環境になる可能性があるので、開発段階で発見できたのは良かったといえばよかったか・・・</p>



<p>Webアプリ開発は長らくやってきたつもりでしたが、まだまだ勉強不足な部分がありました。<br>サーバーサイド、フロントサイド、マイクロサービス etc　そのような環境でもつまらずに開発が続けられるようになりたい・・・</p>


<div id="rinkerid809" class="yyi-rinker-contents  yyi-rinker-postid-809 yyi-rinker-img-m yyi-rinker-catid-16 yyi-rinker-catid-8 ">
	<div class="yyi-rinker-box">
		<div class="yyi-rinker-image">
							<a href="https://www.amazon.co.jp/dp/4908686106?tag=monodon-22&#038;linkCode=ogi&#038;th=1&#038;psc=1" rel="nofollow"><img decoding="async" src="https://m.media-amazon.com/images/I/51gxWVO4BIL._SL160_.jpg" width="112" height="160" class="yyi-rinker-main-img" style="border: none;" loading="lazy"></a>					</div>
		<div class="yyi-rinker-info">
			<div class="yyi-rinker-title">
									<a href="https://www.amazon.co.jp/dp/4908686106?tag=monodon-22&#038;linkCode=ogi&#038;th=1&#038;psc=1" rel="nofollow">Webブラウザセキュリティ Webアプリケーションの安全性を支える仕組みを整理する</a>							</div>
			<div class="yyi-rinker-detail">
							<div class="credit-box">created by&nbsp;<a href="https://oyakosodate.com/rinker/" rel="nofollow noopener" target="_blank" >Rinker</a></div>
										<div class="price-box">
							</div>
						</div>
						<ul class="yyi-rinker-links">
																                    <li class="amazonlink">
						<a href="https://www.amazon.co.jp/gp/search?ie=UTF8&amp;keywords=Cookie+web&amp;tag=monodon-22&amp;index=blended&amp;linkCode=ure&amp;creative=6339" rel="nofollow" class="yyi-rinker-link">Amazon</a>					</li>
													<li class="rakutenlink">
						<a href="https://af.moshimo.com/af/c/click?a_id=3394378&amp;p_id=54&amp;pc_id=54&amp;pl_id=616&amp;url=https%3A%2F%2Fsearch.rakuten.co.jp%2Fsearch%2Fmall%2FCookie%2Bweb%2F%3Ff%3D1%26grp%3Dproduct" rel="nofollow" class="yyi-rinker-link">楽天市場</a><img loading="lazy" decoding="async" src="https://i.moshimo.com/af/i/impression?a_id=3394378&amp;p_id=54&amp;pc_id=54&amp;pl_id=616" width="1" height="1" style="border:none;">					</li>
													<li class="yahoolink">
						<a href="https://af.moshimo.com/af/c/click?a_id=3442618&amp;p_id=1225&amp;pc_id=1925&amp;pl_id=18502&amp;url=https%3A%2F%2Fshopping.yahoo.co.jp%2Fsearch%3Fp%3DCookie%2Bweb" rel="nofollow" class="yyi-rinker-link">Yahooショッピング</a><img loading="lazy" decoding="async" src="https://i.moshimo.com/af/i/impression?a_id=3442618&amp;p_id=1225&amp;pc_id=1925&amp;pl_id=18502" width="1" height="1" style="border:none;">					</li>
				                											</ul>
					</div>
	</div>
</div>


<div id="rinkerid810" class="yyi-rinker-contents  yyi-rinker-postid-810 yyi-rinker-img-m yyi-rinker-catid-16 yyi-rinker-catid-8 ">
	<div class="yyi-rinker-box">
		<div class="yyi-rinker-image">
							<a href="https://www.amazon.co.jp/dp/B09BV2HGN3?tag=monodon-22&#038;linkCode=ogi&#038;th=1&#038;psc=1" rel="nofollow"><img decoding="async" src="https://m.media-amazon.com/images/I/51Y0-P+m94L._SL160_.jpg" width="112" height="160" class="yyi-rinker-main-img" style="border: none;" loading="lazy"></a>					</div>
		<div class="yyi-rinker-info">
			<div class="yyi-rinker-title">
									<a href="https://www.amazon.co.jp/dp/B09BV2HGN3?tag=monodon-22&#038;linkCode=ogi&#038;th=1&#038;psc=1" rel="nofollow">モダンJavaScriptの基本から始める　React実践の教科書　（最新ReactHooks対応）</a>							</div>
			<div class="yyi-rinker-detail">
							<div class="credit-box">created by&nbsp;<a href="https://oyakosodate.com/rinker/" rel="nofollow noopener" target="_blank" >Rinker</a></div>
										<div class="price-box">
							</div>
						</div>
						<ul class="yyi-rinker-links">
																	<li class="amazonkindlelink">
						<a href="https://www.amazon.co.jp/dp/B09BV2HGN3?tag=monodon-22&amp;linkCode=ogi&amp;th=1&amp;psc=1" rel="nofollow" class="yyi-rinker-link">Kindle</a>					</li>
								                    <li class="amazonlink">
						<a href="https://www.amazon.co.jp/gp/search?ie=UTF8&amp;keywords=react&amp;tag=monodon-22&amp;index=blended&amp;linkCode=ure&amp;creative=6339" rel="nofollow" class="yyi-rinker-link">Amazon</a>					</li>
													<li class="rakutenlink">
						<a href="https://af.moshimo.com/af/c/click?a_id=3394378&amp;p_id=54&amp;pc_id=54&amp;pl_id=616&amp;url=https%3A%2F%2Fsearch.rakuten.co.jp%2Fsearch%2Fmall%2Freact%2F%3Ff%3D1%26grp%3Dproduct" rel="nofollow" class="yyi-rinker-link">楽天市場</a><img loading="lazy" decoding="async" src="https://i.moshimo.com/af/i/impression?a_id=3394378&amp;p_id=54&amp;pc_id=54&amp;pl_id=616" width="1" height="1" style="border:none;">					</li>
													<li class="yahoolink">
						<a href="https://af.moshimo.com/af/c/click?a_id=3442618&amp;p_id=1225&amp;pc_id=1925&amp;pl_id=18502&amp;url=https%3A%2F%2Fshopping.yahoo.co.jp%2Fsearch%3Fp%3Dreact" rel="nofollow" class="yyi-rinker-link">Yahooショッピング</a><img loading="lazy" decoding="async" src="https://i.moshimo.com/af/i/impression?a_id=3442618&amp;p_id=1225&amp;pc_id=1925&amp;pl_id=18502" width="1" height="1" style="border:none;">					</li>
				                											</ul>
					</div>
	</div>
</div>
<p>投稿 <a href="https://sheltie-garage.xyz/tech/2023/07/cookie%e3%81%8c%e3%81%aa%e3%81%8b%e3%81%aa%e3%81%8b%e3%81%a7%e3%81%8d%e3%81%9a%e3%81%ab%e3%83%8f%e3%83%9e%e3%81%a3%e3%81%9f%e8%a9%b1/">Reactを利用したWebアプリでCookieがなかなかできずにハマった話</a> は <a href="https://sheltie-garage.xyz/tech">Sheltie Garage Tech</a> に最初に表示されました。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://sheltie-garage.xyz/tech/2023/07/cookie%e3%81%8c%e3%81%aa%e3%81%8b%e3%81%aa%e3%81%8b%e3%81%a7%e3%81%8d%e3%81%9a%e3%81%ab%e3%83%8f%e3%83%9e%e3%81%a3%e3%81%9f%e8%a9%b1/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>React dropzoneを利用してbase64形式で画像をアップし、Goでファイルを保存する</title>
		<link>https://sheltie-garage.xyz/tech/2023/07/react-drop-zone%e3%82%92%e5%88%a9%e7%94%a8%e3%81%97%e3%81%a6base64%e5%bd%a2%e5%bc%8f%e3%81%a7%e7%94%bb%e5%83%8f%e3%82%92%e3%82%a2%e3%83%83%e3%83%97%e3%81%97%e3%80%81go%e3%81%a7%e3%83%95%e3%82%a1/</link>
					<comments>https://sheltie-garage.xyz/tech/2023/07/react-drop-zone%e3%82%92%e5%88%a9%e7%94%a8%e3%81%97%e3%81%a6base64%e5%bd%a2%e5%bc%8f%e3%81%a7%e7%94%bb%e5%83%8f%e3%82%92%e3%82%a2%e3%83%83%e3%83%97%e3%81%97%e3%80%81go%e3%81%a7%e3%83%95%e3%82%a1/#respond</comments>
		
		<dc:creator><![CDATA[monodon]]></dc:creator>
		<pubDate>Sat, 01 Jul 2023 07:48:24 +0000</pubDate>
				<category><![CDATA[Go]]></category>
		<category><![CDATA[React]]></category>
		<guid isPermaLink="false">https://sheltie-garage.xyz/tech/?p=773</guid>

					<description><![CDATA[<p>タイトルのまんまです。個人開発中のWebアプリのため全体のコードを載せることができません。ご了承ください。ポイントとなる部分をポイントポイントで紹介できればと思います。 react-dropzoneを利用して画像ファイル [&#8230;]</p>
<p>投稿 <a href="https://sheltie-garage.xyz/tech/2023/07/react-drop-zone%e3%82%92%e5%88%a9%e7%94%a8%e3%81%97%e3%81%a6base64%e5%bd%a2%e5%bc%8f%e3%81%a7%e7%94%bb%e5%83%8f%e3%82%92%e3%82%a2%e3%83%83%e3%83%97%e3%81%97%e3%80%81go%e3%81%a7%e3%83%95%e3%82%a1/">React dropzoneを利用してbase64形式で画像をアップし、Goでファイルを保存する</a> は <a href="https://sheltie-garage.xyz/tech">Sheltie Garage Tech</a> に最初に表示されました。</p>
]]></description>
										<content:encoded><![CDATA[
<p>タイトルのまんまです。個人開発中のWebアプリのため全体のコードを載せることができません。ご了承ください。<br>ポイントとなる部分をポイントポイントで紹介できればと思います。</p>



<h2 class="wp-block-heading">react-dropzoneを利用して画像ファイルからbase64を取得し、axiosで送信する</h2>



<p>react-dropzoneの利用方法は以下になります<br><a href="https://react-dropzone.js.org/#section-basic-example" target="_blank" rel="noreferrer noopener">https://react-dropzone.js.org/#section-basic-example</a></p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>  const {acceptedFiles, getRootProps, getInputProps} = useDropzone();
  
  const files = acceptedFiles.map(file =&gt; (
    &lt;li key={file.path}&gt;
      {file.path} - {file.size} bytes
    &lt;/li&gt;
  ));</code></pre></div>



<p>react-dropzoneの利用方法を抜粋したのが上のコードです。<br>acceptedFilesに選択した画像ファイルの情報が入ってきます。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>    const fileReader = new FileReader();

    // ファイルをBase64でエンコード
    fileReader.onload = () =&gt; {
      const base64Data = fileReader.result as string;

      // 事前登録APIへリクエストをポスト
      axios
        .post(registerURL, base64Data)
        .then((response) =&gt; {
          console.log(response.data);
        });
    };
    fileReader.readAsDataURL(acceptedFiles[0]);</code></pre></div>



<p>ファイル読み込み時のonloadイベントを利用してbase64形式でデータを取得。<br>axiosを利用してGoで作成されたAPIへPOSTメソッドで送信します。</p>



<p>acceptedFiles[0]としているのは、現在のアプリの想定では画像は1つのみ選択する仕様のため、選択されたファイルの先頭を取得しています。</p>



<h2 class="wp-block-heading">Goでのバックエンド処理</h2>



<p>Goでは送信されたPOSTデータを解析し、画像ファイルとして保存します。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>	imageData := strings.Split(base64Data, &quot;,&quot;)[1]
	decodedData, err := base64.StdEncoding.DecodeString(imageData)</code></pre></div>



<p>strings.Split(base64Data, &#8220;,&#8221;)[1]としているのは、送信されたbase64データの先頭には「data:image/png;base64,」といったデータの種類を表すスキームが含まれているため、純粋なデータ部分のみを取得するためを取得するための処理になります。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>err = os.WriteFile(path+fileName, decodedData, 0644)</code></pre></div>



<p>実際にbase64(デコード済み)のデータを画像ファイルに書き出している部分はこちら。<br>path + fileNameは保存先のファイル名まで含めたフルパスが記載されています。<br>decodedDataはデコード済みのbase64データ、0644はファイルパーミッションとなります。</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="722" src="https://sheltie-garage.xyz/tech/wp-content/uploads/2023/07/スクリーンショット-2023-07-01-16.42.27-1024x722.png" alt="" class="wp-image-774" srcset="https://sheltie-garage.xyz/tech/wp-content/uploads/2023/07/スクリーンショット-2023-07-01-16.42.27-1024x722.png 1024w, https://sheltie-garage.xyz/tech/wp-content/uploads/2023/07/スクリーンショット-2023-07-01-16.42.27-300x211.png 300w, https://sheltie-garage.xyz/tech/wp-content/uploads/2023/07/スクリーンショット-2023-07-01-16.42.27-768x541.png 768w, https://sheltie-garage.xyz/tech/wp-content/uploads/2023/07/スクリーンショット-2023-07-01-16.42.27-1536x1083.png 1536w, https://sheltie-garage.xyz/tech/wp-content/uploads/2023/07/スクリーンショット-2023-07-01-16.42.27-2048x1444.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>主要な部分の抜粋になりますが、「画像をbase64形式で受け取り、Goを利用してファイルを保存する」という流れについては概ね以上のようになります。</p>



<p>ちなみに、当初はreact-dropzoneではなく、MuiFileInput(Material UI File Input)を利用していたのですが、子コンポーネントとして作成したMuiFileInputに対して渡したイベントハンドラがどうやってもうまく起動せず断念しました。<br>react-dropzoneは「多機能すぎて気軽に使えない」ような書き込みを見たのですが、base64形式でファイルを送信する程度であれば、そこまで難しい機能を利用せず実現できます。</p>


<div id="rinkerid775" class="yyi-rinker-contents  yyi-rinker-postid-775 yyi-rinker-img-m yyi-rinker-catid-16 yyi-rinker-catid-8 ">
	<div class="yyi-rinker-box">
		<div class="yyi-rinker-image">
							<a href="https://www.amazon.co.jp/dp/B09BV2HGN3?tag=monodon-22&#038;linkCode=ogi&#038;th=1&#038;psc=1" rel="nofollow"><img decoding="async" src="https://m.media-amazon.com/images/I/51Y0-P+m94L._SL160_.jpg" width="112" height="160" class="yyi-rinker-main-img" style="border: none;" loading="lazy"></a>					</div>
		<div class="yyi-rinker-info">
			<div class="yyi-rinker-title">
									<a href="https://www.amazon.co.jp/dp/B09BV2HGN3?tag=monodon-22&#038;linkCode=ogi&#038;th=1&#038;psc=1" rel="nofollow">モダンJavaScriptの基本から始める　React実践の教科書　（最新ReactHooks対応）</a>							</div>
			<div class="yyi-rinker-detail">
							<div class="credit-box">created by&nbsp;<a href="https://oyakosodate.com/rinker/" rel="nofollow noopener" target="_blank" >Rinker</a></div>
										<div class="price-box">
							</div>
						</div>
						<ul class="yyi-rinker-links">
																	<li class="amazonkindlelink">
						<a href="https://www.amazon.co.jp/dp/B09BV2HGN3?tag=monodon-22&amp;linkCode=ogi&amp;th=1&amp;psc=1" rel="nofollow" class="yyi-rinker-link">Kindle</a>					</li>
								                    <li class="amazonlink">
						<a href="https://www.amazon.co.jp/gp/search?ie=UTF8&amp;keywords=react&amp;tag=monodon-22&amp;index=blended&amp;linkCode=ure&amp;creative=6339" rel="nofollow" class="yyi-rinker-link">Amazon</a>					</li>
													<li class="rakutenlink">
						<a href="https://af.moshimo.com/af/c/click?a_id=3394378&amp;p_id=54&amp;pc_id=54&amp;pl_id=616&amp;url=https%3A%2F%2Fsearch.rakuten.co.jp%2Fsearch%2Fmall%2Freact%2F%3Ff%3D1%26grp%3Dproduct" rel="nofollow" class="yyi-rinker-link">楽天市場</a><img loading="lazy" decoding="async" src="https://i.moshimo.com/af/i/impression?a_id=3394378&amp;p_id=54&amp;pc_id=54&amp;pl_id=616" width="1" height="1" style="border:none;">					</li>
													<li class="yahoolink">
						<a href="https://af.moshimo.com/af/c/click?a_id=3442618&amp;p_id=1225&amp;pc_id=1925&amp;pl_id=18502&amp;url=https%3A%2F%2Fshopping.yahoo.co.jp%2Fsearch%3Fp%3Dreact" rel="nofollow" class="yyi-rinker-link">Yahooショッピング</a><img loading="lazy" decoding="async" src="https://i.moshimo.com/af/i/impression?a_id=3442618&amp;p_id=1225&amp;pc_id=1925&amp;pl_id=18502" width="1" height="1" style="border:none;">					</li>
				                											</ul>
					</div>
	</div>
</div>


<div id="rinkerid645" class="yyi-rinker-contents  yyi-rinker-postid-645 yyi-rinker-img-m yyi-rinker-catid-16 yyi-rinker-catid-8 ">
	<div class="yyi-rinker-box">
		<div class="yyi-rinker-image">
							<a href="https://af.moshimo.com/af/c/click?a_id=3394378&#038;p_id=54&#038;pc_id=54&#038;pl_id=616&#038;url=https%3A%2F%2Fsearch.rakuten.co.jp%2Fsearch%2Fmall%2FGo%25E8%25A8%2580%25E8%25AA%259E%2F%3Ff%3D1%26grp%3Dproduct" rel="nofollow"><img decoding="async" src="https://thumbnail.image.rakuten.co.jp/@0_mall/book/cabinet/9694/9784873119694_1_3.jpg?_ex=128x128" width="128" height="128" class="yyi-rinker-main-img" style="border: none;" loading="lazy"></a><img loading="lazy" decoding="async" src="https://i.moshimo.com/af/i/impression?a_id=3394378&amp;p_id=54&amp;pc_id=54&amp;pl_id=616" width="1" height="1" style="border:none;">					</div>
		<div class="yyi-rinker-info">
			<div class="yyi-rinker-title">
									<a href="https://af.moshimo.com/af/c/click?a_id=3394378&#038;p_id=54&#038;pc_id=54&#038;pl_id=616&#038;url=https%3A%2F%2Fsearch.rakuten.co.jp%2Fsearch%2Fmall%2FGo%25E8%25A8%2580%25E8%25AA%259E%2F%3Ff%3D1%26grp%3Dproduct" rel="nofollow">実用 Go言語 システム開発の現場で知っておきたいアドバイス [ 渋川 よしき ]</a><img loading="lazy" decoding="async" src="https://i.moshimo.com/af/i/impression?a_id=3394378&amp;p_id=54&amp;pc_id=54&amp;pl_id=616" width="1" height="1" style="border:none;">							</div>
			<div class="yyi-rinker-detail">
							<div class="credit-box">created by&nbsp;<a href="https://oyakosodate.com/rinker/" rel="nofollow noopener" target="_blank" >Rinker</a></div>
										<div class="price-box">
							<span title="" class="price">¥3,960</span>
															<span class="price_at">(2026/04/30 06:22:26時点&nbsp;楽天市場調べ-</span><span title="このサイトで掲載されている情報は当サイトの作成者により運営されています。価格、販売可能情報は、変更される場合があります。購入時に楽天市場店舗（www.rakuten.co.jp）に表示されている価格がその商品の販売に適用されます。">詳細)</span>
																	</div>
						</div>
						<ul class="yyi-rinker-links">
																                    <li class="amazonlink">
						<a href="https://www.amazon.co.jp/gp/search?ie=UTF8&amp;keywords=Go%E8%A8%80%E8%AA%9E&amp;tag=monodon-22&amp;index=blended&amp;linkCode=ure&amp;creative=6339" rel="nofollow" class="yyi-rinker-link">Amazon</a>					</li>
													<li class="rakutenlink">
						<a href="https://af.moshimo.com/af/c/click?a_id=3394378&amp;p_id=54&amp;pc_id=54&amp;pl_id=616&amp;url=https%3A%2F%2Fsearch.rakuten.co.jp%2Fsearch%2Fmall%2FGo%25E8%25A8%2580%25E8%25AA%259E%2F%3Ff%3D1%26grp%3Dproduct" rel="nofollow" class="yyi-rinker-link">楽天市場</a><img loading="lazy" decoding="async" src="https://i.moshimo.com/af/i/impression?a_id=3394378&amp;p_id=54&amp;pc_id=54&amp;pl_id=616" width="1" height="1" style="border:none;">					</li>
													<li class="yahoolink">
						<a href="https://af.moshimo.com/af/c/click?a_id=3442618&amp;p_id=1225&amp;pc_id=1925&amp;pl_id=18502&amp;url=https%3A%2F%2Fshopping.yahoo.co.jp%2Fsearch%3Fp%3DGo%25E8%25A8%2580%25E8%25AA%259E" rel="nofollow" class="yyi-rinker-link">Yahooショッピング</a><img loading="lazy" decoding="async" src="https://i.moshimo.com/af/i/impression?a_id=3442618&amp;p_id=1225&amp;pc_id=1925&amp;pl_id=18502" width="1" height="1" style="border:none;">					</li>
				                											</ul>
					</div>
	</div>
</div>
<p>投稿 <a href="https://sheltie-garage.xyz/tech/2023/07/react-drop-zone%e3%82%92%e5%88%a9%e7%94%a8%e3%81%97%e3%81%a6base64%e5%bd%a2%e5%bc%8f%e3%81%a7%e7%94%bb%e5%83%8f%e3%82%92%e3%82%a2%e3%83%83%e3%83%97%e3%81%97%e3%80%81go%e3%81%a7%e3%83%95%e3%82%a1/">React dropzoneを利用してbase64形式で画像をアップし、Goでファイルを保存する</a> は <a href="https://sheltie-garage.xyz/tech">Sheltie Garage Tech</a> に最初に表示されました。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://sheltie-garage.xyz/tech/2023/07/react-drop-zone%e3%82%92%e5%88%a9%e7%94%a8%e3%81%97%e3%81%a6base64%e5%bd%a2%e5%bc%8f%e3%81%a7%e7%94%bb%e5%83%8f%e3%82%92%e3%82%a2%e3%83%83%e3%83%97%e3%81%97%e3%80%81go%e3%81%a7%e3%83%95%e3%82%a1/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Reactを始めてみる</title>
		<link>https://sheltie-garage.xyz/tech/2022/06/react%e3%82%92%e5%a7%8b%e3%82%81%e3%81%a6%e3%81%bf%e3%82%8b/</link>
					<comments>https://sheltie-garage.xyz/tech/2022/06/react%e3%82%92%e5%a7%8b%e3%82%81%e3%81%a6%e3%81%bf%e3%82%8b/#respond</comments>
		
		<dc:creator><![CDATA[monodon]]></dc:creator>
		<pubDate>Sat, 25 Jun 2022 06:46:51 +0000</pubDate>
				<category><![CDATA[React]]></category>
		<guid isPermaLink="false">https://sheltie-garage.xyz/tech/?p=129</guid>

					<description><![CDATA[<p>仕事でReact開発を行うことになったので、基礎の基礎であるReactプロジェクト作成と初期画面の表示まで行ってみます。環境は以下のとおりです・Intel Mac MacOS12 Monterey・npm 8.12.2  [&#8230;]</p>
<p>投稿 <a href="https://sheltie-garage.xyz/tech/2022/06/react%e3%82%92%e5%a7%8b%e3%82%81%e3%81%a6%e3%81%bf%e3%82%8b/">Reactを始めてみる</a> は <a href="https://sheltie-garage.xyz/tech">Sheltie Garage Tech</a> に最初に表示されました。</p>
]]></description>
										<content:encoded><![CDATA[
<p>仕事でReact開発を行うことになったので、基礎の基礎であるReactプロジェクト作成と初期画面の表示まで行ってみます。<br>環境は以下のとおりです<br>・Intel Mac MacOS12 Monterey<br>・npm 8.12.2</p>



<h2 class="wp-block-heading">Reactプロジェクトの作成</h2>



<p>Reactプロジェクトの作成から、サンプルページの実行までは以下の3行を実行すればよいだけです</p>



<pre class="wp-block-code"><code>npx create-react-app hello-world
cd hello-world
npm start</code></pre>



<p>※npxはスペルミスではなく、npm5.2から同梱されているコマンドです。<a href="https://dev.classmethod.jp/articles/node-npm-npx-getting-started/" target="_blank" rel="noreferrer noopener">こちらの記事</a>が参考になりました</p>



<p>上記のコマンドを実行するとブラウザが勝手に起動し、「http://localhost:3000」にアクセスし、以下の画面が表示されると思います。</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="991" src="https://sheltie-garage.xyz/tech/wp-content/uploads/2022/06/20220625_001-1024x991.png" alt="" class="wp-image-130" srcset="https://sheltie-garage.xyz/tech/wp-content/uploads/2022/06/20220625_001-1024x991.png 1024w, https://sheltie-garage.xyz/tech/wp-content/uploads/2022/06/20220625_001-300x290.png 300w, https://sheltie-garage.xyz/tech/wp-content/uploads/2022/06/20220625_001-768x743.png 768w, https://sheltie-garage.xyz/tech/wp-content/uploads/2022/06/20220625_001.png 1184w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p></p>



<p>これでReactプロジェクトの作成は完了です。結構簡単に作成出来ますね！</p>



<h2 class="wp-block-heading">ちょっといじってみる</h2>



<p>画面に表示されている通り、プロジェクト内のApp.jsを編集して保存すると、自動でリロードされて変更が反映されます。<br>少しいじってみます。<br>プロジェクトの構成は以下のようになっています。</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="622" src="https://sheltie-garage.xyz/tech/wp-content/uploads/2022/06/20220625_002-1024x622.png" alt="" class="wp-image-131" srcset="https://sheltie-garage.xyz/tech/wp-content/uploads/2022/06/20220625_002-1024x622.png 1024w, https://sheltie-garage.xyz/tech/wp-content/uploads/2022/06/20220625_002-300x182.png 300w, https://sheltie-garage.xyz/tech/wp-content/uploads/2022/06/20220625_002-768x467.png 768w, https://sheltie-garage.xyz/tech/wp-content/uploads/2022/06/20220625_002-1536x933.png 1536w, https://sheltie-garage.xyz/tech/wp-content/uploads/2022/06/20220625_002.png 1824w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p><strong>Learn React</strong>と記載されている部分を<strong>ハローワールド</strong>に書き換えてみました</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="561" src="https://sheltie-garage.xyz/tech/wp-content/uploads/2022/06/20220625_005-1024x561.png" alt="" class="wp-image-132" srcset="https://sheltie-garage.xyz/tech/wp-content/uploads/2022/06/20220625_005-1024x561.png 1024w, https://sheltie-garage.xyz/tech/wp-content/uploads/2022/06/20220625_005-300x164.png 300w, https://sheltie-garage.xyz/tech/wp-content/uploads/2022/06/20220625_005-768x421.png 768w, https://sheltie-garage.xyz/tech/wp-content/uploads/2022/06/20220625_005-1536x841.png 1536w, https://sheltie-garage.xyz/tech/wp-content/uploads/2022/06/20220625_005-2048x1122.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>ご覧の通り、メッセージが切り替わりました。保存したタイミングで自動でリロードが走るので、手動リロードも必要ありません</p>



<h2 class="wp-block-heading">ちょっとだけJSXに触れてみる</h2>



<p>JSXはjavaScript構文を拡張したものです。Reactコンポーネントを記述する際に用いられています。<br>公式の説明は<a href="https://ja.reactjs.org/docs/introducing-jsx.html" target="_blank" rel="noreferrer noopener">こちらから</a>どうぞ！</p>



<p>以下のようにプログラムを書き換えてみました</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="715" src="https://sheltie-garage.xyz/tech/wp-content/uploads/2022/06/20220625_004-1024x715.png" alt="" class="wp-image-133" srcset="https://sheltie-garage.xyz/tech/wp-content/uploads/2022/06/20220625_004-1024x715.png 1024w, https://sheltie-garage.xyz/tech/wp-content/uploads/2022/06/20220625_004-300x209.png 300w, https://sheltie-garage.xyz/tech/wp-content/uploads/2022/06/20220625_004-768x536.png 768w, https://sheltie-garage.xyz/tech/wp-content/uploads/2022/06/20220625_004-1536x1072.png 1536w, https://sheltie-garage.xyz/tech/wp-content/uploads/2022/06/20220625_004.png 1822w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>ご覧の通り、H1タグを変数に大入し、その変数を<strong>{}</strong>を利用して参照しています。<br>JSX構文ではこの通り、変数にタグ情報を設定できたり、その内容を{}を利用して参照したり出来ます。<br>上記の改修を行うと、以下のような画面になります。</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="919" src="https://sheltie-garage.xyz/tech/wp-content/uploads/2022/06/20220625_003-1024x919.png" alt="" class="wp-image-134" srcset="https://sheltie-garage.xyz/tech/wp-content/uploads/2022/06/20220625_003-1024x919.png 1024w, https://sheltie-garage.xyz/tech/wp-content/uploads/2022/06/20220625_003-300x269.png 300w, https://sheltie-garage.xyz/tech/wp-content/uploads/2022/06/20220625_003-768x689.png 768w, https://sheltie-garage.xyz/tech/wp-content/uploads/2022/06/20220625_003.png 1288w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>変数に代入したH1タグが展開されて、画面に表示されました<br>HTMLタグが変数に代入できるという感覚はなんとも不思議な漢字ですが、JSX構文では有効な記述となっています</p>



<h2 class="wp-block-heading">以上</h2>



<p>とりあえずReactのプロジェクトを作成し、少し改造するところまで記事にしました。<br>ちょっとだけ触った漢字だと、Vueよりも扱いやすい印象を受けたので、今後は趣味開発でもReactを採用していきたいと思いました。</p>


<div id="rinkerid135" class="yyi-rinker-contents  yyi-rinker-postid-135 yyi-rinker-img-m yyi-rinker-catid-8 ">
	<div class="yyi-rinker-box">
		<div class="yyi-rinker-image">
							<a href="https://af.moshimo.com/af/c/click?a_id=3394378&#038;p_id=54&#038;pc_id=54&#038;pl_id=616&#038;url=https%3A%2F%2Fsearch.rakuten.co.jp%2Fsearch%2Fmall%2FReact%2F%3Ff%3D1%26grp%3Dproduct" rel="nofollow"><img decoding="async" src="https://thumbnail.image.rakuten.co.jp/@0_mall/book/cabinet/0722/9784815610722_1_9.jpg?_ex=128x128" width="128" height="128" class="yyi-rinker-main-img" style="border: none;" loading="lazy"></a><img loading="lazy" decoding="async" src="https://i.moshimo.com/af/i/impression?a_id=3394378&amp;p_id=54&amp;pc_id=54&amp;pl_id=616" width="1" height="1" style="border:none;">					</div>
		<div class="yyi-rinker-info">
			<div class="yyi-rinker-title">
									<a href="https://af.moshimo.com/af/c/click?a_id=3394378&#038;p_id=54&#038;pc_id=54&#038;pl_id=616&#038;url=https%3A%2F%2Fsearch.rakuten.co.jp%2Fsearch%2Fmall%2FReact%2F%3Ff%3D1%26grp%3Dproduct" rel="nofollow">モダンJavaScriptの基本から始める　React実践の教科書 （最新ReactHooks対応） [ じゃけぇ（岡田　拓巳） ]</a><img loading="lazy" decoding="async" src="https://i.moshimo.com/af/i/impression?a_id=3394378&amp;p_id=54&amp;pc_id=54&amp;pl_id=616" width="1" height="1" style="border:none;">							</div>
			<div class="yyi-rinker-detail">
							<div class="credit-box">created by&nbsp;<a href="https://oyakosodate.com/rinker/" rel="nofollow noopener" target="_blank" >Rinker</a></div>
										<div class="price-box">
							<span title="" class="price">¥2,860</span>
															<span class="price_at">(2026/04/30 15:35:45時点&nbsp;楽天市場調べ-</span><span title="このサイトで掲載されている情報は当サイトの作成者により運営されています。価格、販売可能情報は、変更される場合があります。購入時に楽天市場店舗（www.rakuten.co.jp）に表示されている価格がその商品の販売に適用されます。">詳細)</span>
																	</div>
						</div>
						<ul class="yyi-rinker-links">
																                    <li class="amazonlink">
						<a href="https://www.amazon.co.jp/gp/search?ie=UTF8&amp;keywords=React&amp;tag=monodon-22&amp;index=blended&amp;linkCode=ure&amp;creative=6339" rel="nofollow" class="yyi-rinker-link">Amazon</a>					</li>
													<li class="rakutenlink">
						<a href="https://af.moshimo.com/af/c/click?a_id=3394378&amp;p_id=54&amp;pc_id=54&amp;pl_id=616&amp;url=https%3A%2F%2Fsearch.rakuten.co.jp%2Fsearch%2Fmall%2FReact%2F%3Ff%3D1%26grp%3Dproduct" rel="nofollow" class="yyi-rinker-link">楽天市場</a><img loading="lazy" decoding="async" src="https://i.moshimo.com/af/i/impression?a_id=3394378&amp;p_id=54&amp;pc_id=54&amp;pl_id=616" width="1" height="1" style="border:none;">					</li>
													<li class="yahoolink">
						<a href="https://af.moshimo.com/af/c/click?a_id=3442618&amp;p_id=1225&amp;pc_id=1925&amp;pl_id=18502&amp;url=https%3A%2F%2Fshopping.yahoo.co.jp%2Fsearch%3Fp%3DReact" rel="nofollow" class="yyi-rinker-link">Yahooショッピング</a><img loading="lazy" decoding="async" src="https://i.moshimo.com/af/i/impression?a_id=3442618&amp;p_id=1225&amp;pc_id=1925&amp;pl_id=18502" width="1" height="1" style="border:none;">					</li>
				                											</ul>
					</div>
	</div>
</div>


<div id="rinkerid136" class="yyi-rinker-contents  yyi-rinker-postid-136 yyi-rinker-img-m yyi-rinker-catid-8 ">
	<div class="yyi-rinker-box">
		<div class="yyi-rinker-image">
							<a href="https://af.moshimo.com/af/c/click?a_id=3394378&#038;p_id=54&#038;pc_id=54&#038;pl_id=616&#038;url=https%3A%2F%2Fsearch.rakuten.co.jp%2Fsearch%2Fmall%2FReact%2F%3Ff%3D1%26grp%3Dproduct" rel="nofollow"><img decoding="async" src="https://thumbnail.image.rakuten.co.jp/@0_mall/book/cabinet/9380/9784873119380_1_2.jpg?_ex=128x128" width="128" height="128" class="yyi-rinker-main-img" style="border: none;" loading="lazy"></a><img loading="lazy" decoding="async" src="https://i.moshimo.com/af/i/impression?a_id=3394378&amp;p_id=54&amp;pc_id=54&amp;pl_id=616" width="1" height="1" style="border:none;">					</div>
		<div class="yyi-rinker-info">
			<div class="yyi-rinker-title">
									<a href="https://af.moshimo.com/af/c/click?a_id=3394378&#038;p_id=54&#038;pc_id=54&#038;pl_id=616&#038;url=https%3A%2F%2Fsearch.rakuten.co.jp%2Fsearch%2Fmall%2FReact%2F%3Ff%3D1%26grp%3Dproduct" rel="nofollow">Reactハンズオンラーニング 第2版 Webアプリケーション開発のベストプラクティス [ Alex Banks ]</a><img loading="lazy" decoding="async" src="https://i.moshimo.com/af/i/impression?a_id=3394378&amp;p_id=54&amp;pc_id=54&amp;pl_id=616" width="1" height="1" style="border:none;">							</div>
			<div class="yyi-rinker-detail">
							<div class="credit-box">created by&nbsp;<a href="https://oyakosodate.com/rinker/" rel="nofollow noopener" target="_blank" >Rinker</a></div>
										<div class="price-box">
							<span title="" class="price">¥3,740</span>
															<span class="price_at">(2026/04/30 15:35:46時点&nbsp;楽天市場調べ-</span><span title="このサイトで掲載されている情報は当サイトの作成者により運営されています。価格、販売可能情報は、変更される場合があります。購入時に楽天市場店舗（www.rakuten.co.jp）に表示されている価格がその商品の販売に適用されます。">詳細)</span>
																	</div>
						</div>
						<ul class="yyi-rinker-links">
																                    <li class="amazonlink">
						<a href="https://www.amazon.co.jp/gp/search?ie=UTF8&amp;keywords=React&amp;tag=monodon-22&amp;index=blended&amp;linkCode=ure&amp;creative=6339" rel="nofollow" class="yyi-rinker-link">Amazon</a>					</li>
													<li class="rakutenlink">
						<a href="https://af.moshimo.com/af/c/click?a_id=3394378&amp;p_id=54&amp;pc_id=54&amp;pl_id=616&amp;url=https%3A%2F%2Fsearch.rakuten.co.jp%2Fsearch%2Fmall%2FReact%2F%3Ff%3D1%26grp%3Dproduct" rel="nofollow" class="yyi-rinker-link">楽天市場</a><img loading="lazy" decoding="async" src="https://i.moshimo.com/af/i/impression?a_id=3394378&amp;p_id=54&amp;pc_id=54&amp;pl_id=616" width="1" height="1" style="border:none;">					</li>
													<li class="yahoolink">
						<a href="https://af.moshimo.com/af/c/click?a_id=3442618&amp;p_id=1225&amp;pc_id=1925&amp;pl_id=18502&amp;url=https%3A%2F%2Fshopping.yahoo.co.jp%2Fsearch%3Fp%3DReact" rel="nofollow" class="yyi-rinker-link">Yahooショッピング</a><img loading="lazy" decoding="async" src="https://i.moshimo.com/af/i/impression?a_id=3442618&amp;p_id=1225&amp;pc_id=1925&amp;pl_id=18502" width="1" height="1" style="border:none;">					</li>
				                											</ul>
					</div>
	</div>
</div>
<p>投稿 <a href="https://sheltie-garage.xyz/tech/2022/06/react%e3%82%92%e5%a7%8b%e3%82%81%e3%81%a6%e3%81%bf%e3%82%8b/">Reactを始めてみる</a> は <a href="https://sheltie-garage.xyz/tech">Sheltie Garage Tech</a> に最初に表示されました。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://sheltie-garage.xyz/tech/2022/06/react%e3%82%92%e5%a7%8b%e3%82%81%e3%81%a6%e3%81%bf%e3%82%8b/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
