2022-10-14
Posted by
最終更新: 2023-03-05
残念ながら今回はロジックメインなので凝ったcssは書かないですが
待ちに待ったfrontendです
現在のファイル構成はこのようになっているはずです
main
page
.git
node_modules
pages
api
_app.tsx
index.tsx
public
styles
.eslintrc.json
next.config.js
next-env.d.ts
package.json
README.md
tsconfig.json
yarn.lock
api
venv
app.py
pagesのfileがそのままurlのpathになります
index.tsxはindex.htmlと同じように
127.0.0.1:3000/でアクセスできます(今はまだ実行してないから入れませんが
ただhtmlと違うのは.htmlなどが要らないのです。
例えば test.tsx なら /test で入れます
[id].tsxなどはflaskのrouteで言う<id>と同じような機能になります
info
https://127.0.0.1:3000/* と同じ
今回で言えば
https://127.0.0.1:3000/10 などの任意のurlでアクセス出来ます
逆にid.tsxは
https://127.0.0.1:3000/id からしかアクセス出来ません
さて、前回言ったアプリに必要な物は以下の物でしたよね
1. https://example.com/<id>(<id>は例えば"g48Wa"などが入る) 等のurlにアクセスすると設定したwebsiteに飛ばさ れること
2. httos://example.com にアクセスすると新しくurlを作れる事
とりあえずindex.tsxは既に有るので2はこれを改造したら行けそうです
1は新しくファイルを作りましょう
フォルダ名は[id].tsxにしましょう
参考までに、下現在のフォルダ
main
page
.git
node_modules
pages
api
_app.tsx
[id].tsx
index.tsx
public
styles
.eslintrc.json
next.config.js
next-env.d.ts
package.json
README.md
tsconfig.json
yarn.lock
api
venv
app.py
[id].tsxの中身を書く前にaxiosを入れておきましょう
axiosはPromiseベースのHTTPクライアントです
簡単に言うとapiなどを呼び出すのに使うライブラリです
今回は先ほど作ったbackendのapiを呼び出すのに使います
axiosを入れるのは簡単でコマンドを実行するだけです
新しくcmd(command prompt)かてterminal等を開きfrontendのフォルダーに移動します
A:\abc>cd A:\abc\osaka\main\page
apple@apple ~ % cd /abc/osaka/main/page
次は
A:\abc\osaka\main\page>npm install axios
added 9 packages, and audited 246 packages in 2s
79 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
A:\abc\osaka\main\page>
apple@apple page % npm install axios
added 9 packages, and audited 246 packages in 2s
79 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
apple@apple page %
と入力すればインストールが終わりました
せっかくcmdを開いたのですからfrontendを実行しましょう
A:\abc\osaka\main\page>npm run dev
added 9 packages, and audited 246 packages in 2s
79 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
D:\docs\trash\my-app>npm run dev
> [email protected] dev
> next dev
ready - started server on 0.0.0.0:3000, url: http://localhost:3000
event - compiled client and server successfully in 1979 ms (154 modules)
apple@apple page % npm run dev
added 9 packages, and audited 246 packages in 2s
79 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
apple@apple page % npm run dev
> [email protected] dev
> next dev
ready - started server on 0.0.0.0:3000, url: http://localhost:3000
event - compiled client and server successfully in 1979 ms (154 modules)
info
Ctrl + C で出れます
macbookの場合は
command + . で出れます
これで127.0.0.1:3000にアクセスすると表示されるはずです
さぁ[id].tsxを書きましょう
書きましょうとは言ったもののやはり書く前にある程度どのようなものを書くのかを考えましょう
1. backendからidを元にurlを取得する
2. もしurlがあるならそのurlにリダイレクトする
3. ないなら404を表示する
簡単そうですね
とりあえずリダイレクトのテストと404の表示だけしてしまいましょう
import { GetServerSideProps } from 'next'
import DefaultErrorPage from 'next/error'
import React from 'react'
import axios from 'axios'
export const getServerSideProps: GetServerSideProps = async (context: any) => {
return {
redirect: {
permanent: false
,destination: "https://exmaple.com"
}
}
}
export default function none() {
return (<DefaultErrorPage statusCode={404} />)
}
これで https://127.0.0.1:3000/[id](例 127.0.0.1:3000/test) にアクセスするとexample.comにリダイレクトされるはずです
試しにreturnを変更したら
import { GetServerSideProps } from 'next'
import DefaultErrorPage from 'next/error'
import React from 'react'
import axios from 'axios'
export const getServerSideProps: GetServerSideProps = async (context: any) => {
return {
props:{}
}
}
export default function none() {
return (<DefaultErrorPage statusCode={404} />)
}
404になるはずです
今はリダイレクトに戻しておきましょう
簡単な解説をしておくと
import { GetServerSideProps } from 'next'
import DefaultErrorPage from 'next/error'
import React from 'react'
import axios from 'axios'
export const getServerSideProps: GetServerSideProps = async (context: any) => {
return {
redirect: {
permanent: false
,destination: "https://exmaple.com"
}
}
}
export default function none() {
return (<DefaultErrorPage statusCode={404} />)
}
code 1の1行目はリダイレクトなどをするために必要な関数を定義するのに有ったら便利な物です
2行目は404を返すのに使います普通に書いても良いですが今回はサクッと作りたいのでdefaultのを使っています
3行目は今は使いませんがそのうちbackendからurlを持ってくるのに使います
code 2はリダイレクトするのに使いますasyncなのはその後非同期処理を同期処理にしたいからです
又引数のcontextは/[id]のidを取得するのに使います、今回は使いませんがその他にも/?id=10などのurl queryも取得できます
code 3 code 2 でリダイレクトされなかったときは404が返されます
さぁ次はbackendからurlを取得しましょう
その前にurlからidを/[id].tsxなどのクエリーは以下のような感じで取得できます
context.query.id
いよいよbackendから取得しましょう
今回は簡単なgetで事足ります
const res = await axios.get(`http://127.0.0.1:5000/get/${context.query.id}`)
axios.get(url)
でデータを取得できます
送られてきたデータをresに代入しています
awaitはasyncの関数内のみで使用でき非同期処理を同期処理に出来ます
なぜ同期処理にするかと言うと
同期処理をしないとpromisが返されるからです
promisは送信した物であって送信して帰ってきた物では無いのです
今回は送られてきた物が必要なので同期処理をしています
promisが送られてきて困ったらとりあえずasyncからawaitで解決できます
backendが送るのは以下のjsonですが送られてきたデータの中のdataにurlが入っていますその為取り出すには以下のようにする必要が有ります
{"url":"https://example.com"}
どうやってurlを取り出すべきか
と、なります
後はurlがundefinedでは無い時だけリダイレクトするだけです
ここまでで以下のようなコードがかけます
import { GetServerSideProps } from 'next'
import DefaultErrorPage from 'next/error'
import React from 'react'
import axios from 'axios'
export const getServerSideProps: GetServerSideProps = async (context: any) => {
const res = await axios.get(`http://127.0.0.1:5000/get/${context.query.id}`)
if ( !res.data.url ) {
return {
props: {}
}
}
return {
redirect: {
permanent: false
,destination: res.data.url
}
}
}
export default function none() {
return (<DefaultErrorPage statusCode={404} />)
}
試しに 127.0.0.1:3000/test にアクセスしてみましょう
アクセスできました
後は新しくurlを作る機能を作ればfrontendは終わりですね
index.tsxを改造して作ろうと思いましたが
面倒なので一度index.tsxを一度すべて消してしまいましょう
解説の本筋とはあまり関係が無いのでサクッとformを作ってしまいました
後は関数、postを書くだけです
info
これからも関数はconstで定義します
functionと大差無いですがconstの方が管理やバグが少なく抑えられると言われているのでconstを使用しています
一番の違いはfunctionは最初に定義しても最後に定義しても何処からでも呼び出せるのに対しconstは定義をした後からしか呼び出せませんvarとletのような物です
warning
errorが出ますがnetwork errorなら想定内です
import type { NextPage } from "next"
import { useState } from "react"
import axios from "axios"
const Index: NextPage = () => {
const [result, setResult] = useState("")
const [url, setUrl] = useState("")
const post = async () => {}
return <div>
<input value={url} onChange={ (e) => setUrl(e.target.value)} type="text" />
<p>{result}</p>
<button onClick={post}>create</button>
</div>
}
export default Index
一応簡単な解説をしておきます
import type { NextPage } from "next"
import { useState } from "react"
import axios from "axios"
const Index: NextPage = () => {
const [result, setResult] = useState("") //後で送られてきた短縮urlを入れる箱
const [url, setUrl] = useState("") //入力したurlを入れる箱
const post = async () => {} //仮定義
// 最低限必要なelement達
return <div>
<input value={url} onChange={ (e) => setUrl(e.target.value)} type="text" />
<p>{result}</p>
<button onClick={post}>create</button>
</div>
}
export default Index
code 1で読み込んで
code 2でformに必要な最低限を定義して
code 3でexportする
解説?と呼べるのか不思議なものではあったがとりあえずこれで良いだろう
後は先ほどと同じようaxiosを使ってにpostしよう!(さっきはget
const post = async () => {
const res = await axios.post("http://127.0.0.1:5000/create", {
body: JSON.stringify({"url":url})
})
setResult(res.data.url)
}
さっきと違い axios.get
からaxios.post
にかわっている
それはさっきは一方的に貰うだけだったが今回はurlを与える必要があるからだ
urlは第二の引数でbodyの中に入れて送っている
JSON.stringify
はオブジェクトなどをjsonに変換して返す
bodyはjsonでなければならないのだ
つまりやっていることは127.0.0.1:5000/create にjsonを送って送られてきたjsonをresultとして表示させているだけなのだ
{"url":url}
ここまでで以下のようなコードになっているだろう(index.tsx
import type { NextPage } from "next"
import { useState } from "react"
import axios from "axios"
const Index: NextPage = () => {
const [result, setResult] = useState("")
const [url, setUrl] = useState("")
const post = async () => {
const res = await axios.post("http://127.0.0.1:5000/create", {
body: JSON.stringify({"url":url})
})
setResult(res.data.url)
}
return <div>
<input value={url} onChange={(e) => setUrl(e.target.value)} type="text" />
<p>{result}</p>
<button onClick={post}>create</button>
</div>
}
export default Index
warning
errorが出ますがnetwork errorなら想定内です
ほよょ?
エラーが出ましたね
AxiosError: Network Error
と出ています
ネットワークに接続しているか確認してしまいそうなerrorですがlocalhostなので関係ありません
コードを確認してもfrontend,backendともに特に問題ありません
何故でしょうか
次回、Errorの原因はCORS
エラーの原因は何なのでしょうか?乞うご期待
このドキュメントどう?