106日目②:debug成功!ユーザー(developers)のプロフィールを表示させる&React Hooksのdebug修正

昨日のdebug修正を行い、登録したユーザー(developers)のプロフィールが表示されるようになりました。また、他ファイルにも間違いがあり、debugしました。

debugしていて気づいた一番大きな間違いは、ナビゲーションバーのファイル(Navbar.js)上で、テスト用に書いたコードをそのまま残してしまっていた(本来なら消さなければならない)ことです。昨日は何度かコードを見直したのですが、気づきませんでした。今日はすぐ気が付きましたので、やはり「疲れていない状態で見直す」ことがすごく大事なのかもしれません。

というわけで、プロフィールを表示させるためのコード(正しいもの)です。

①新フォルダに新ファイル作成してプロフィールが表示されるようにする client/src/components/profiles/Profiles.js

componentsの中に新しいフォルダ「profiles」を作成して、新しいファイル、Profiles.jsを作成しました。

React HooksのuseEffectを使用して、ユーザーのプロフィールを表示できるようにコードを書きました。ローディング中はスピナーを表示、ローディングが終わったらDevelopersと表示されるようになっています。

useEffectの部分は、最後の[]部分は最初空欄だったのですが、それではエラー表示が出てしまうということで、[getProfiles]と修正しました。

  1. import React, { Fragment, useEffect } from "react";
  2. import PropTypes from "prop-types";
  3. import { connect } from "react-redux";
  4. import Spinner from "../layout/Spinner";
  5. import ProfileItem from "./ProfileItem";
  6. import { getProfiles } from "../../actions/profile";
  7. const Profiles = ({ getProfiles, profile: { profiles, loading } }) => {
  8. useEffect(() => {
  9. getProfiles();
  10. }, [getProfiles]);
  11. return (
  12. <Fragment>
  13. {loading ? (
  14. <Spinner />
  15. ) : (
  16. <Fragment>
  17. <h1 className='large text-primary'>Developers</h1>
  18. <p className='lead'>
  19. <i className='fab fa-connectdevelop' /> Browse and connect with
  20. developers
  21. </p>
  22. <div className='profiles'>
  23. {profiles.length > 0 ? (
  24. profiles.map(profile => (
  25. <ProfileItem key={profile._id} profile={profile} />
  26. ))
  27. ) : (
  28. <h4>No profiles found...</h4>
  29. )}
  30. </div>
  31. </Fragment>
  32. )}
  33. </Fragment>
  34. );
  35. };
  36. Profiles.propTypes = {
  37. getProfiles: PropTypes.func.isRequired,
  38. profile: PropTypes.object.isRequired
  39. };
  40. const mapStateToProps = state => ({
  41. profile: state.profile
  42. });
  43. export default connect(
  44. mapStateToProps,
  45. { getProfiles }
  46. )(Profiles);
import React, { Fragment, useEffect } from "react";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import Spinner from "../layout/Spinner";
import ProfileItem from "./ProfileItem";
import { getProfiles } from "../../actions/profile";

const Profiles = ({ getProfiles, profile: { profiles, loading } }) => {
  useEffect(() => {
    getProfiles();
  }, [getProfiles]);

  return (
    <Fragment>
      {loading ? (
        <Spinner />
      ) : (
        <Fragment>
          <h1 className='large text-primary'>Developers</h1>
          <p className='lead'>
            <i className='fab fa-connectdevelop' /> Browse and connect with
            developers
          </p>
          <div className='profiles'>
            {profiles.length > 0 ? (
              profiles.map(profile => (
                <ProfileItem key={profile._id} profile={profile} />
              ))
            ) : (
              <h4>No profiles found...</h4>
            )}
          </div>
        </Fragment>
      )}
    </Fragment>
  );
};

Profiles.propTypes = {
  getProfiles: PropTypes.func.isRequired,
  profile: PropTypes.object.isRequired
};

const mapStateToProps = state => ({
  profile: state.profile
});

export default connect(
  mapStateToProps,
  { getProfiles }
)(Profiles);

 

②新しいファイルを作成して、プロフィールの詳細が表示されるようにするclient/src/components/profiles/ProfileItem.js

先程作成した「profiles」フォルダ内にProfileItem.jsというファイルを作成しました。そこで、プロフィール詳細である、ユーザーのID・名前・アバター、ステイタス(現在の状態)、会社、場所、スキルが表示されるようコーディングしました。

スキルは4つをMAXとするために、sliceとmapを使用しています。

  1. import React from "react";
  2. import { Link } from "react-router-dom";
  3. import PropTypes from "prop-types";
  4. const ProfileItem = ({
  5. profile: {
  6. user: { _id, name, avatar },
  7. status,
  8. company,
  9. location,
  10. skills
  11. }
  12. }) => {
  13. return (
  14. <div className='profile bg-light'>
  15. <img src={avatar} alt='' className='round-img' />
  16. <div>
  17. <h2>{name}</h2>
  18. <p>
  19. {status} {company && <span> at {company}</span>}
  20. </p>
  21. <p className='my-1'>{location && <span>{location}</span>}</p>
  22. <Link to={`/profile/${_id}`} className='btn btn-primary'>
  23. View Profile
  24. </Link>
  25. </div>
  26. <ul>
  27. {skills.slice(0, 4).map((skill, index) => (
  28. <li key={index} className='text-primary'>
  29. <i className='fas fa-check' /> {skill}
  30. </li>
  31. ))}
  32. </ul>
  33. </div>
  34. );
  35. };
  36. ProfileItem.propTypes = {
  37. profile: PropTypes.object.isRequired
  38. };
  39. export default ProfileItem;
import React from "react";
import { Link } from "react-router-dom";
import PropTypes from "prop-types";

const ProfileItem = ({
  profile: {
    user: { _id, name, avatar },
    status,
    company,
    location,
    skills
  }
}) => {
  return (
    <div className='profile bg-light'>
      <img src={avatar} alt='' className='round-img' />
      <div>
        <h2>{name}</h2>
        <p>
          {status} {company && <span> at {company}</span>}
        </p>
        <p className='my-1'>{location && <span>{location}</span>}</p>
        <Link to={`/profile/${_id}`} className='btn btn-primary'>
          View Profile
        </Link>
      </div>
      <ul>
        {skills.slice(0, 4).map((skill, index) => (
          <li key={index} className='text-primary'>
            <i className='fas fa-check' /> {skill}
          </li>
        ))}
      </ul>
    </div>
  );
};

ProfileItem.propTypes = {
  profile: PropTypes.object.isRequired
};

export default ProfileItem;

 

③App.jsに新しいファイル情報を書き加える

まず、import部分にprofilesフォルダのProfiles.jsの情報を書き加えました。

  1. import Profiles from "./components/profiles/Profiles";
import Profiles from "./components/profiles/Profiles";

const AppのSwitch内に新しいRouteを書き加えます。(profilesの一行のみ)

  1. const App = () => {
  2. useEffect(() => {
  3. store.dispatch(loadUser());
  4. }, []);
  5. return (
  6. <Provider store={store}>
  7. <Router>
  8. <Fragment>
  9. <Navbar />
  10. <Route exact path='/' component={Landing} />
  11. <section className='container'>
  12. <Alert />
  13. <Switch>
  14. <Route exact path='/register' component={Register} />
  15. <Route exact path='/login' component={Login} />
  16. <Route exact path='/profiles' component={Profiles} />
  17. <PrivateRoute exact path='/dashboard' component={Dashboard} />
  18. <PrivateRoute
  19. exact
  20. path='/create-profile'
  21. component={CreateProfile}
  22. />
  23. <PrivateRoute
  24. exact
  25. path='/edit-profile'
  26. component={EditProfile}
  27. />
  28. <PrivateRoute
  29. exact
  30. path='/add-experience'
  31. component={AddExperience}
  32. />
  33. <PrivateRoute
  34. exact
  35. path='/add-education'
  36. component={AddEducation}
  37. />
  38. </Switch>
  39. </section>
  40. </Fragment>
  41. </Router>
  42. </Provider>
  43. );
  44. };
const App = () => {
  useEffect(() => {
    store.dispatch(loadUser());
  }, []);

  return (
    <Provider store={store}>
      <Router>
        <Fragment>
          <Navbar />
          <Route exact path='/' component={Landing} />
          <section className='container'>
            <Alert />
            <Switch>
              <Route exact path='/register' component={Register} />
              <Route exact path='/login' component={Login} />
              <Route exact path='/profiles' component={Profiles} />
              <PrivateRoute exact path='/dashboard' component={Dashboard} />
              <PrivateRoute
                exact
                path='/create-profile'
                component={CreateProfile}
              />
              <PrivateRoute
                exact
                path='/edit-profile'
                component={EditProfile}
              />
              <PrivateRoute
                exact
                path='/add-experience'
                component={AddExperience}
              />
              <PrivateRoute
                exact
                path='/add-education'
                component={AddEducation}
              />
            </Switch>
          </section>
        </Fragment>
      </Router>
    </Provider>
  );
};

 

④ナビゲーションバーにprofilesページへのリンクを書き加え、developersのプロフィール情報を表示できるようコードを書き加える(debugした部分)client/src/components/layout/Navbar.js

本日debugしていて気づいたのが、このファイルにテスト用に書いていたコードを消していなかったということです。

プロフィールのページへのリンクだけで良かったところ、/#!というテスト用ページへのリンクを消していなかったので、昨日おかしなことになっていました。正しいコードを書くことができて本日はスッキリです。

  1. import React, { Fragment } from "react";
  2. import { Link } from "react-router-dom";
  3. import { connect } from "react-redux";
  4. import PropTypes from "prop-types";
  5. import { logout } from "../../actions/auth";
  6. const Navbar = ({ auth: { isAuthenticated, loading }, logout }) => {
  7. const authLinks = (
  8. <ul>
  9. <li>
  10. <Link to='/profiles'>Developers</Link>
  11. </li>
  12. <li>
  13. <Link to='/dashboard'>
  14. <i className='fas fa-user' />
  15. {""}
  16. <span ClassName='hide-sm'>Dashboard</span>
  17. </Link>
  18. </li>
  19. <li>
  20. <a onClick={logout} href='#!'>
  21. <i className='fas fa-sign-out-alt' />
  22. {""}
  23. <span ClassName='hide-sm'>Logout</span>
  24. </a>
  25. </li>
  26. </ul>
  27. );
  28. const guestLinks = (
  29. <ul>
  30. <li>
  31. <Link to='/profiles'>Developers</Link>
  32. </li>
  33. <li>
  34. <Link to='/register'>Register</Link>
  35. </li>
  36. <li>
  37. <Link to='/login'>Login</Link>
  38. </li>
  39. </ul>
  40. );
  41. return (
  42. <nav className='navbar bg-dark'>
  43. <h1>
  44. <Link to='/'>
  45. <i className='fas fa-code' /> DevConnector
  46. </Link>
  47. </h1>
  48. {!loading && (
  49. <Fragment>{isAuthenticated ? authLinks : guestLinks}</Fragment>
  50. )}
  51. </nav>
  52. );
  53. };
  54. Navbar.propTypes = {
  55. logout: PropTypes.func.isRequired,
  56. auth: PropTypes.object.isRequired
  57. };
  58. const mapStateToProps = state => ({
  59. auth: state.auth
  60. });
  61. export default connect(
  62. mapStateToProps,
  63. { logout }
  64. )(Navbar);
import React, { Fragment } from "react";
import { Link } from "react-router-dom";
import { connect } from "react-redux";
import PropTypes from "prop-types";
import { logout } from "../../actions/auth";

const Navbar = ({ auth: { isAuthenticated, loading }, logout }) => {
  const authLinks = (
    <ul>
      <li>
        <Link to='/profiles'>Developers</Link>
      </li>
      <li>
        <Link to='/dashboard'>
          <i className='fas fa-user' />
          {""}
          <span ClassName='hide-sm'>Dashboard</span>
        </Link>
      </li>
      <li>
        <a onClick={logout} href='#!'>
          <i className='fas fa-sign-out-alt' />
          {""}
          <span ClassName='hide-sm'>Logout</span>
        </a>
      </li>
    </ul>
  );

  const guestLinks = (
    <ul>
      <li>
        <Link to='/profiles'>Developers</Link>
      </li>
      <li>
        <Link to='/register'>Register</Link>
      </li>
      <li>
        <Link to='/login'>Login</Link>
      </li>
    </ul>
  );

  return (
    <nav className='navbar bg-dark'>
      <h1>
        <Link to='/'>
          <i className='fas fa-code' /> DevConnector
        </Link>
      </h1>
      {!loading && (
        <Fragment>{isAuthenticated ? authLinks : guestLinks}</Fragment>
      )}
    </nav>
  );
};

Navbar.propTypes = {
  logout: PropTypes.func.isRequired,
  auth: PropTypes.object.isRequired
};

const mapStateToProps = state => ({
  auth: state.auth
});

export default connect(
  mapStateToProps,
  { logout }
)(Navbar);

これで、プロフィールのページに、登録したユーザー(developers=開発者)が並んで表示されるようになりました。今日になって新しい目でチェックしてみると意外とシンプルなミスでした。debugする時は疲れていない状態で何がおかしいのか考えると良いなと思いました。

⑤その他に気づいたミスをdebugした。import { Link } from "react-router-dom"を使用している時のリンクの飛ばし方を間違えている部分があったので修正

これはまた別ファイルの全く別件のミスなのですが、import { Link } from "react-router-dom";を使用している時は、<Link to="/リンク先ファイル名”></Link>としなければならないところ、aタグ(a href)で囲んだ時と同じようにリンク先を”http~.html"と書いてしまっていた箇所を発見しましたので、修正しました。

具体的には、AddExperience.jsというファイルのこの部分です。Go Backをクリックでダッシュボードに飛ぶようになっています。

  1. <Link className='btn btn-light my-1' to='/dashboard'>
  2. Go Back
  3. </Link>
<Link className='btn btn-light my-1' to='/dashboard'>
          Go Back
        </Link>

 

現在使用している教材と学習時間:本日の学習時間2.5時間(復習とdebugのみ)
Udemy:MERN Stack Front To Back: Full Stack React, Redux & Node.js by Brad Traversy

★Section10:Profile Display

-Lec 53 Finish Profile Actions & Reducer(前のブログ記事の内容)

-Lec54 Display Profiles (開発者=developersのプロフィールを表示するページの作成。昨日間違えた部分をdebugして修正。)

-Lec 55 Addressing The Console Warnings (ここまでの講座でエラーが出ている箇所を修正。React Hooksの修正含む。)

進捗状況:76%

学習時間2.5時間

★参考にした本★

「React.js & Next.js超入門」掌田津耶乃 (秀和システム)

Section4-1: Reduxを使ってみよう

関連キーワード
  • 131日目~134日目:Udemyで一番人気のGit (&GitHub) コースを修了!学習した内容・学習にかかった時間とおすすめ度をご紹介: Completed Git course by Udemy "Git Complete: The definitive, step-by-step guide to Git" by Jason Taylor: Highly recommended to both beginner & intermediate leaner
  • 121日目~130日目:Udemyで新しいReactコース学習とGit & GitHubのコースを受講し始める #100dayofcode Round 2
  • 120日目:プログラミング学習100日チャレンジの完了とこれからの学習&ブログ記事:100days of code completed & from now on
  • 119日目:完成したWebアプリケーションの公開(Devconnector deployed on Heroku)
  • 118日目:Udemy講座の感想口コミ&自分に合った講座の選び方ポイント:Mern Stack Front to Back: Full Stack React, Redux & Node.js by Brad Traversy
  • 117日目:完成!Herokuへのデプロイ成功:Heroku CLIのインストールからWebアプリデプロイまで。Herokuの使い方と、package.jsonとgitコマンドではまったところと解決方法
おすすめの記事