【インターンレポート】フロントエンド編~Typescript×Reactでwebアプリケーションを作る~
こんにちは、C-Style株式会社の菅野です!
今回はインターンシップで行ったwebアプリケーション作成について実際に行ったことを書いていこうと思います!
今回のインターンで作成したもの
アイシャドウ専門のWebアプリケーションを作成しました。
概要としては、メイクアップした写真に使ったコスメをタグ付けできるものです。
背景
女性がコスメを調べるとき、著名人やインフルエンサーが使っているものを購入する傾向があります。
そこで、ユーザーが自分のメイクした写真をアップしその写真に対してタグづけできる機能を用いることで気になるコスメを探しやすくなるWebアプリケーションを作成することになりました。
技術選定
主な技術スタックは以下の通りです。
プログラミング言語:TypeScript(フレームワーク:Express, React)
ORマッパー:Prisma
まず必要なユースケースを洗い出しました。その上で、私ともう1人のインターン生が担当したフロントエンドでは以下の機能を実装しました。
タイムライン機能
タグ付け機能(期間内に実装できませんでした…)
検索機能(下に同じく)
Typescript×React
Typescript×Reactの環境構築
create-react-appを使用して新規プロジェクトをセットアップする場合、
「--typescript 」パラメーターを使用することで、そのプロジェクトはTypeScriptを使用してセットアップできます。
npx create-react-app [プロジェクト名] --typescript
これでTypescriptのプロジェクトを作成できます。
簡単ですね!
この先の詳細設定については長くなってしまうため、今回は触れません。。
Typescript×Reactを使用して機能実装
タグ付け機能が実装できなかったので、今回はタイムライン機能の実装について行ったことを書きます。
初学者ゆえソースコードが汚いですがご容赦ください。
まず、タイムラインを実装するにあたって以下のコンポーネントを作成しました。
このWebアプリケーションのトップページの完成形はこのような形で、赤で囲われている部分がタイムライン、青で囲われている部分はカテゴリー、黄色で囲われている部分はサイドメニュー、緑で囲われている部分はユーザー,オレンジで囲われている部分はヘッダー、紫で囲われている部分はサーチバーコンポーネントで構成されています。
タイムラインコンポーネント
JSON形式で取得した値をタイムラインのように並べて表示する機能です。
type Post = {
article_id:number;
product_image_path:string;
created_at:string;
}
export const TimeLine = () => {
const urlAPI = 'http://localhost:3001/articles/timeline/recommend';
const [datas, setDatas] = useState([]);
console.log(axios.defaults.baseURL)
useEffect( () => {
axios.get(urlAPI).then(response =>
setDatas(response.data)).catch(error => console.log(error))
},[])
console.log(datas)
return (
<div className="Apple">
<ImageList sx={{ width: 1, height: 1}} cols={3}>
{datas.map((data :Post,index) => (
<ImageListItem key={data.article_id} style={{ margin:"10%"}}>
<a> <img className="imge" style={{width:"100%"}} src={data.product_image_path}/> </a>
</ImageListItem>
))}
</ImageList>
</div>
);
}
取得するJSONデータに一致するPostという型を定義します。
タイムラインコンポーネント内で状態変数をuseState()で定義し、useEffect内でAPIを叩きます。
今回はバックエンド側でAPIを作成してもらい、それを弾くことによりデータを取得しています。
戻り値でタイムラインぽくなるように脳筋コードを書きました。(今回はMaterial-UIのImageListというコンポーネントを利用しました)
各画像をクリックするとプロダクトページに遷移する予定でした。
カテゴリーコンポーネント
カテゴリーを一覧表示するためのコンポーネントです。
今回はパーソナルカラー4シーズンを各項目としました。
const Category: React.FC = () =>{
return(
<div>
<Grid className="categories">
<h2>探す</h2>
<Link to="/ywpage"><Grid className="categorynames">春</Grid> </Link>
<Link to="/blpage"><Grid className="categorynames">夏</Grid> </Link>
<Link to="/ywpage"><Grid className="categorynames">秋</Grid> </Link>
<Link to="/blpage"><Grid className="categorynames">冬</Grid> </Link>
</Grid>
</div>
);
}
export default Category
各項目をクリックすると別ページに遷移するようになっています。
Material-UIのGridで成形しています
ユーザーコンポーネント
ユーザーを一覧表示するためのコンポーネントです。
type User = {
username:string;
main_image:string;*/
}
export const User = () =>{
const urlAPI = 'https://jsonplaceholder.typicode.com/users';
const [datas, setDatas] = useState([]);
console.log(axios.defaults.baseURL)
useEffect( () => {
axios.get(urlAPI).then(response =>
setDatas(response.data)).catch(error => console.log(error))
},[])
console.log(datas)
return(
<div>
<Grid className="users" >
<h2>ユーザー</h2>
{datas.map((data :Post,index) => (
<Grid className="usernames">{data.username}</Grid>
))}
</Grid>
</div>
);
}
行っていることは、タイムラインコンポーネントとほとんど同じです。
取得するJSONデータに一致するUserという型を定義します。
ユーザーコンポーネント内で状態変数をuseState()で定義し、useEffect内でAPIを叩きます。
ユーザーのAPIはJSONPlaceholderのusersを利用しています。
サーチバーコンポーネント
検索ワード入力し,タイムラインコンポーネントに渡す予定でした。
時間がなく作成しきれず...。
export const Search = () =>{
const [text, setText] = useState("");
return(
<div >
<form method="get" action="#" className="search_container">
<input type="text" value={text} placeholder=" キーワード検索" onChange={(event) => setText(event.target.value)}/>
<Link to="/not"><input type="submit" value="検索"/></Link>
<SearchTL/>
</form>
</div>);
サイドメニューコンポーネント
サーチバー、カテゴリー、ユーザーコンポーネントを含むコンポーネントです。
export const Sidemenue = () =>{
return (
<div className="side">
<div className="side-top">
<Search/>
<Category/>
</div>
<div className="side-un">
<User/>
</div>
</div>
);
}
コンポーネントを並べ、クラスを定義し,CSSファイルで成型しています。
ヘッダーコンポーネント
画面上部に「新規会員登録」「ログイン」を表示するためのコンポーネントです。
export const Header = () =>{
return(
<>
<header className="header">
<div>
<button className="button">新規会員登録</button>
<button className="button">ログイン</button>
</div>
</header>
</>
);
}
ほとんどHTMLです。(不甲斐ない…。)
トップページコンポーネント
今まで作成したコンポーネントを画面に表示します。
export const TopPage = () =>{
return (
<div >
<Header/>
<main className="main">
<div className = "item">
<Sidemenue/>
</div>
<div className = "item">
<TimeLine/>
</div>
</main>
</div>
);
}
ほとんどHTMLです(再び)
TypeScriptよりCSSに力を入れて、トップページがより見やすくなるようにしました。
インターンで得た学び
複数人でのプロジェクトの経験が少ないということもあり、分担や進捗確認、各担当部分の合致などがとても大変でした。
また、当初の目標であるところまで作成することができず力不足、勉強不足を感じました。もっとやれることもあったと思い、とても心残りです。。。
今回のインターンを通して大きく成長することができたと感じています!
慢心せず、いろいろなことに挑戦し力をつけていきたいです!