- 投稿日:2020-06-04T22:04:49+09:00
Reactでaxiousを使って詳細ページを作る�
今回はaxiousを使ってタスク詳細ページを作る
APIを記述
src/service/v1ApRequest.jsimport axios from 'axios' // Taskの詳細ページのAPI export const getTaskSubscriptionDetail = (id = ":id") => axios.get(`${API_ROOT}/task_subscriptions/${id}`)APIのリクエストがたくさんあるときは一つのファイルにまとめておくとわかりやすい
タスク詳細ページ作成
src/containers/TaskDetailPage.jsimport { getTaskSubscriptionDetail } from '../services/v1ApiRequest' import { SET_TASKSUBSCRIPTION } from '../constants/actionTypes' import TaskSubscription from '../models/taskSubscription' class TaskDetail extends Component { componentDidMount() { // this.props.match.params.idは // ..../path/to/:id の :idの部分をとってくれる // ..../path/to/:hoge_id だったら // this.props.match.params.hoge_id で取得できる // mapDispatchToPropsで定義したAPIを呼び出してStoreに保存するための関数を実行 this.props.fetchTaskDetail(this.props.match.params.id); } render() { return ( <div className={styles.taskName}>{this.props.taskSubscription.task.name}</div> ) } } const mapStateToProps = ({ app, taskSubscription }) => ({ isLoading: app.isLoading, taskSubscription: taskSubscription.selected // 4. APIのレスポンスがここに入る }) //APIの結果をactionとしてdispatchする→コンポーネント側でやるならmapDispatchPropsを使う const mapDispatchToProps = dispatch => ({ fetchTaskDetail: (id) => { // 1. API呼び出して getTaskSubscriptionDetail(id) .then((res) => { // 2. レスポンスを受け取って console.log(res.data); // 3. dispatchにレスポンスを変換したもの(API)をpayloadにセットしたアクションをReducerへ運ばせる dispatch({ type: SET_TASKSUBSCRIPTION, //payload: res.data だとスネークケースになるので、以下でキャメルケースにする payload: TaskSubscription.newFromApiResponse(res.data) }) }) .catch((error) => { // API読んでる最中にエラーが発生したらこっちが実行される console.log(error); }); } }) export default connect( mapStateToProps, mapDispatchToProps )(withRouter(TaskDetail))ルーティング
src/routes/index.jstasks: (id) => `/tasks${id ? `/${id}` : "" }`, // idがないときは一覧(/tasks)、idがあるときは詳細(/tasks/:is)のページへ
- 投稿日:2020-06-04T20:15:30+09:00
microCMSのプレビュー機能をGatsby.jsで使う
Gatsby.jsは言わずと知れたReact製の静的サイトジェネレーターですが、ビルド時にページを生成するという性質ゆえに、microCMSのプレビュー機能を使うにはひと工夫必要だったので共有したいと思います。
この機能をご存知の方はコードの部分からご覧ください。microCMSの記事プレビュー機能について
microCMSのプレビュー機能について少し説明しておくと、記事執筆画面で
公開ボタンの左にある画面プレビューを押した時に、執筆中の記事が実際にはどのように表示されるか確認できる機能です。仕組みとしては、という感じです。
詳しくはhttps://microcms.io/blog/draftkey_and_preview/ に掲載されています。何が問題でどうしたらいいのか?
この機能をGatsbyで使用する時、考えなければならないのは、Gatsby.jsの記事データは基本ビルド時に生成された物なので、
「画面プレビュー」クリック時に送られてきたcontentId
とdraftKey
を基に記事データをリアルタイムに取得して、表示する仕組みを作らないといけない。ということです。ということでコード
前置きはそのくらいにしてコードはこのようになりました。
pages/previewPage.jsximport React, { useState, useEffect } from "react"; import { getSearchParams } from "gatsby-query-params"; //...その他コンポーネントなど function previewPage() { //microCMS側に設定するurlはhttps://xxxxxx.com/previewPage/?contentId={CONTENT_ID}&draftKey={DRAFT_KEY}みたいな感じ const queryParams = getSearchParams(); //queryParamsには //{contentId:"xxxx", //draftKey:"xxxx"} //というようなデータが入ります。 const contentId = queryParams.contentId; const draftKey = queryParams.draftKey; const [postData, setPostData] = useState(null);//最初、postDataにはnullが入ります。 useEffect(() => { if (!postData) { fetch( `https://xxxxxxxxx.microcms.io/api/v1/blogs/${contentId}?draftKey=${draftKey}`, { headers: { "X-API-KEY": "xxxxxxx-xxxx-xxxxx-xxxx-xxxxxxxx", }, } ) .then((response) => { if (response.ok) { return response.json(); } }) .then((json) => { postData = setPostData(json);//ここで、postDataに取得したコンテンツが格納されます。 }); } else { return function cleanup() { console.log("done"); }; } }); return ( <div dangerouslySetInnerHTML={{ __html: postData ? postData.sentence : "", }} ></div> ); } export default previewPage;このようなページを作成することで、アクセスした時にurlクエリパラメータの情報を基にコンテンツをとってきてくれます。
以下、詳しく説明していきます。API部分について
microCMSはPOSTとGETのAPI-KEYが違うのでGETのAPIが露出しても大して問題はないですが、なんとなく気持ちが悪いので、
X-API-KEY: "xxxxx-xxxx"としている部分とmicroCMSのurl部分は実際には環境変数に置き換えるのが望ましいです。環境変数の使い方に関してはこちらの記事の中でも説明しているので是非ご覧ください。
gatsby-query-params
について2行目に登場する
gatsby-query-params
はこちらです。
使用するにはターミナルでnpm i gatsby-query-params
してください。コメントアウト部分にもありますが、
getSearchParams
によって、urlクエリパラメータの情報をqueryParams
にオブジェクト形式で格納しています。
useState
useEffect
についてこれらはReactのhookで、詳しい説明はこちらにあります。
useEffect
の中で、↑で取得したクエリパラメータを基にmicroCMSにデータを取得しにいき、取得できたら、それをpostData
に格納しています。
responce.ok
についてこれがないとmicroCMSのレスポンスが404の時(useStateがnullの間)返ってくる空文字列
""
を処理しようとしてしまい、jsonオブジェクトでないのでエラーが出てしまいます。レンダリング部分について
return()
内のpostData ? postData.sentence : ''
としている部分で、postDataに↑でとってきた記事データが格納されたら、それが表示されるようになっています。postData.sentence
と書いていますが、sentence
の部分はmicroCMSで定義した表示したいデータのフィールドIDが入ります。レンダリング部分は他の記事ページのレイアウトに合わせて、煮るなり焼くなりしてください!まとめ
サイトを見にきた人が、
/今回作ったページ
と打つとアクセスできてしまいますが、contentsIdとdraftKeyがないので何も表示されないですし、一応は問題ないと思います。色々と改善の余地はありそうですが、とりあえずこれで投稿前の記事をプレビューで確認できるので、是非活用してみてください!
- 投稿日:2020-06-04T00:19:12+09:00
Reactでstateの変更が反映されない
起こったこと
Reactで親コンポーネントでー行った、stateの変更が子コンポーネントで反映されません。
具体的には親コンポーネントは子コンポーネント1と子コンポーネント2を持っています。
子コンポーネント1で親のstateを変更し、その結果を子コンポーネント2で表示させています。解決策
公式ドキュメントにちゃんと書いてありました。
補足
props を state にコピーしないでください。これはよくある間違いです。
constructor(props) {
super(props);
// してはいけません
this.state = { color: props.color };
}
この問題はそれが不要(代わりに this.props.color を直接使用することができるため)であり、バグの作成につながる(color プロパティの更新は state に反映されないため)ことです。意図的にプロパティの更新を無視したい場合にのみ、このパターンを使用してください。その場合は、プロパティの名前を initialColor または defaultColor に変更してください。その後、必要に応じてキーを変更することで、コンポーネントにその内部の state を「リセット」させることができます。
もしあなたが props に依存する何らかの state が必要だと思うなら、どうすればいいのか学ぶために私達の派生 state を避けることについてのブログ記事を読んでください。
propsの値をconstructorの中で初期値として与えると、子コンポーネントは親のstateの変更を感知できないようです。
多くのサイトでこのような書き方をしていたので、結構間違えている人も多いと思います。結局、
constructor(props) { super(props); this.state = {postUser: props.postUser}; }としているのをやめて、直接子コンポーネント内で
props.postUser
を使えば解決です。
super(props);
を消すと子コンポーネントでprops
が使えなくなるので、これは残しておきます。教訓
結局、公式が一番強い。