102日目②:ダッシュボードのプロフィール編集ができるように設定する:Edit Profile on Dashboard

新しいファイルDashboardActions.jsとEditProfile.jsを作成して、ダッシュボードでさらに詳しいプロフィール編集が行えるように設定しました。

①DashboardActions.jsを作成して、プロフィールの編集、経験を追加、学歴が追加できるようにする (client/src/components/dashboard/DashboardActions.js)

まずは、ダッシュボードの見た目を変えていきます。(実際に経験や学歴が追加できるように内容設定は次回のレクチャーで習うとのことです。)

import React from "react";
import { Link } from "react-router-dom";

const DashboardActions = () => {
  return (
    <div className='dash-buttons'>
      <Link to='/edit-profile' className='btn btn-light'>
        <i className='fas fa-user-circle text-primary' /> Edit Profile
      </Link>
      <Link to='/add-experience' className='btn btn-light'>
        <i className='fab fa-black-tie text-primary' /> Add Experience
      </Link>
      <Link to='/add-education' className='btn btn-light'>
        <i className='fas fa-graduation-cap text-primary' /> Add Education
      </Link>
    </div>
  );
};

export default DashboardActions;

 

②Dashboard.jsを書き換えて、先程作成したDashboardActions.jsと繋ぐ(client/src/components/dashboard/Dashboard.js)

importと<Fragment>を使用して、先程作成したDashboardActions.jsと繋ぎました。

import React, { Fragment, useEffect } from "react";
import { Link } from "react-router-dom";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import Spinner from "../layout/Spinner";
import DashboardActions from "./DashboardActions";
import { getCurrentProfile } from "../../actions/profile";

const Dashboard = ({
  getCurrentProfile,
  auth: { user },
  profile: { profile, loading }
}) => {
  // eslint-disable-next-line
  useEffect(() => {
    getCurrentProfile();
  }, []);

  return loading && profile === null ? (
    <Spinner />
  ) : (
    <Fragment>
      <h1 className='large text-primary'>Dashboard</h1>
      <p className='lead'>
        <i className='fas fa-user' /> Welcome {user && user.name}
      </p>
      {profile !== null ? (
        <Fragment>
          <DashboardActions />
        </Fragment>
      ) : (
        <Fragment>
          <p>You have not yet setup a profile, please add some info</p>
          <Link to='/create-profile' className='btn btn-primary my-1'>
            Create Profile
          </Link>
        </Fragment>
      )}
    </Fragment>
  );
};

Dashboard.propTypes = {
  getCurrentProfile: PropTypes.func.isRequired,
  auth: PropTypes.object.isRequired,
  profile: PropTypes.object.isRequired
};

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

export default connect(
  mapStateToProps,
  { getCurrentProfile }
)(Dashboard);

 

③新しいファイルEditProfile.jsを作成して、プロフィールの編集が行えるようにする (client/src/components/profile-form/EditProfile.js)

元々のコードはまず先日作成したCreateProfile.jsからコピペして持ってきました。CreateProfileと書いていたところを全てEdicProfileと書き直しています。また、プロフィールを編集するためには、現在のプロフィール情報も必要となるので、最初のimport部分で{getCurrentProfile} としています。

こちらも、<a href=""></a>コードは<Link to='/  '></Link>に変更しています。

useEffectの後のsetFormData部分のコードについては、少しまどろっこしい印象がありますが、後ほど書き換え予定です。

import React, { useState, Fragment, useEffect } from "react";
import { Link, withRouter } from "react-router-dom";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import { createProfile, getCurrentProfile } from "../../actions/profile";

const EditProfile = ({
  profile: { profile, loading },
  createProfile,
  getCurrentProfile,
  history
}) => {
  const [formData, setFormData] = useState({
    company: "",
    website: "",
    location: "",
    status: "",
    skills: "",
    githubusername: "",
    bio: "",
    twitter: "",
    facebook: "",
    linkedin: "",
    youtube: "",
    instagram: ""
  });

  const [displaySocialImputs, toggleSocialImputs] = useState(false);

  useEffect(() => {
    getCurrentProfile();

    setFormData({
      company: loading || !profile.company ? "" : profile.company,
      website: loading || !profile.website ? "" : profile.website,
      location: loading || !profile.location ? "" : profile.location,
      status: loading || !profile.status ? "" : profile.status,
      skills: loading || !profile.skills ? "" : profile.skills.join(","),
      githubusername:
        loading || !profile.githubusername ? "" : profile.githubusername,
      bio: loading || !profile.bio ? "" : profile.bio,
      twitter: loading || !profile.social ? "" : profile.social.twitter,
      facebook: loading || !profile.social ? "" : profile.social.facebook,
      linkedin: loading || !profile.social ? "" : profile.social.linkedin,
      youtube: loading || !profile.social ? "" : profile.social.youtube,
      instagram: loading || !profile.social ? "" : profile.social.instagram
    });
  }, [loading]);

  const {
    company,
    website,
    location,
    status,
    skills,
    githubusername,
    bio,
    twitter,
    facebook,
    linkedin,
    youtube,
    instagram
  } = formData;

  const onChange = e =>
    setFormData({ ...formData, [e.target.name]: e.target.value });

  const onSubmit = e => {
    e.preventDefault();
    createProfile(formData, history, true);
  };

  return (
    <Fragment>
      <h1 className='large text-primary'>Create Your Profile</h1>
      <p className='lead'>
        <i className='fas fa-user' /> Let's get some information to make your
        profile stand out
      </p>
      <small>* = required field</small>
      <form className='form' onSubmit={e => onSubmit(e)}>
        <div className='form-group'>
          <select name='status' value={status} onChange={e => onChange(e)}>
            <option value='0'>* Select Professional Status</option>
            <option value='Developer'>Developer</option>
            <option value='Junior Developer'>Junior Developer</option>
            <option value='Senior Developer'>Senior Developer</option>
            <option value='Manager'>Manager</option>
            <option value='Student or Learning'>Student or Learning</option>
            <option value='Instructor'>Instructor or Teacher</option>
            <option value='Intern'>Intern</option>
            <option value='Other'>Other</option>
          </select>
          <small className='form-text'>
            Give us an idea of where you are at in your career
          </small>
        </div>
        <div className='form-group'>
          <input
            type='text'
            placeholder='Company'
            name='company'
            value={company}
            onChange={e => onChange(e)}
          />
          <small className='form-text'>
            Could be your own company or one you work for
          </small>
        </div>
        <div className='form-group'>
          <input
            type='text'
            placeholder='Website'
            name='website'
            value={website}
            onChange={e => onChange(e)}
          />
          <small className='form-text'>
            Could be your own or a company website
          </small>
        </div>
        <div className='form-group'>
          <input
            type='text'
            placeholder='Location'
            name='location'
            value={location}
            onChange={e => onChange(e)}
          />
          <small className='form-text'>
            City & state suggested (eg. Boston, MA)
          </small>
        </div>
        <div className='form-group'>
          <input
            type='text'
            placeholder='* Skills'
            name='skills'
            value={skills}
            onChange={e => onChange(e)}
          />
          <small className='form-text'>
            Please use comma separated values (eg. HTML,CSS,JavaScript,PHP)
          </small>
        </div>
        <div className='form-group'>
          <input
            type='text'
            placeholder='Github Username'
            name='githubusername'
            value={githubusername}
            onChange={e => onChange(e)}
          />
          <small className='form-text'>
            If you want your latest repos and a Github link, include your
            username
          </small>
        </div>
        <div className='form-group'>
          <textarea
            placeholder='A short bio of yourself'
            name='bio'
            value={bio}
            onChange={e => onChange(e)}
          />
          <small className='form-text'>Tell us a little about yourself</small>
        </div>

        <div className='my-2'>
          <button
            onClick={() => toggleSocialImputs(!displaySocialImputs)}
            type='button'
            className='btn btn-light'
          >
            Add Social Network Links
          </button>
          <span>Optional</span>
        </div>

        {displaySocialImputs && (
          <Fragment>
            <div className='form-group social-input'>
              <i className='fab fa-twitter fa-2x' />
              <input
                type='text'
                placeholder='Twitter URL'
                name='twitter'
                value={twitter}
                onChange={e => onChange(e)}
              />
            </div>

            <div className='form-group social-input'>
              <i className='fab fa-facebook fa-2x' />
              <input
                type='text'
                placeholder='Facebook URL'
                name='facebook'
                value={facebook}
                onChange={e => onChange(e)}
              />
            </div>

            <div className='form-group social-input'>
              <i className='fab fa-youtube fa-2x' />
              <input
                type='text'
                placeholder='YouTube URL'
                name='youtube'
                value={youtube}
                onChange={e => onChange(e)}
              />
            </div>

            <div className='form-group social-input'>
              <i className='fab fa-linkedin fa-2x' />
              <input
                type='text'
                placeholder='Linkedin URL'
                name='linkedin'
                value={linkedin}
                onChange={e => onChange(e)}
              />
            </div>

            <div className='form-group social-input'>
              <i className='fab fa-instagram fa-2x' />
              <input
                type='text'
                placeholder='Instagram URL'
                name='instagram'
                value={instagram}
                onChange={e => onChange(e)}
              />
            </div>
          </Fragment>
        )}

        <input type='submit' className='btn btn-primary my-1' />
        <Link className='btn btn-light my-1' to='/dashboard'>
          Go Back
        </Link>
      </form>
    </Fragment>
  );
};

EditProfile.propTypes = {
  createProfile: PropTypes.func.isRequired,
  getCurrentProfile: PropTypes.func.isRequired,
  profile: PropTypes.object.isRequired
};

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

export default connect(
  mapStateToProps,
  { createProfile, getCurrentProfile }
)(withRouter(EditProfile));

④最後にApp.jsを編集して本日の学習は完了!(import editProfileとPrivateRouteの書き足し)

本日作業した部分をApp.jsに書き加えました。具体的には。新しいファイルeditProfile.jsをインポートしたことと、/edit-profileへのPrivateRoute作成です。これにて本日の学習は完了です!

(一部、前回作成したCreateProfile.jsのコードに誤りが合ったので修正。)

次回は、experience(経験)とeducation(学歴・教育)の部分を作成していきます。

import React, { Fragment, useEffect } from "react";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import Navbar from "./components/layout/Navbar";
import Landing from "./components/layout/Landing";
import Register from "./components/auth/Register";
import Login from "./components/auth/Login";
import Alert from "./components/layout/Alert";
import Dashboard from "./components/dashboard/Dashboard";
import CreateProfile from "./components/profile-form/CreateProfile";
import editProfile from "./components/profile-form/editProfile";
import PrivateRoute from "./components/routing/PrivateRoute";

//Redux

import { Provider } from "react-redux";
import store from "./store";
import { loadUser } from "./actions/auth";
import setAuthToken from "./utils/setAuthToken";

import "./App.css";

if (localStorage.token) {
  setAuthToken(localStorage.token);
}

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} />
              <PrivateRoute exact path='/dashboard' component={Dashboard} />
              <PrivateRoute
                exact
                path='/create-profile'
                component={CreateProfile}
              />
              <PrivateRoute
                exact
                path='/edit-profile'
                component={editProfile}
              />
            </Switch>
          </section>
        </Fragment>
      </Router>
    </Provider>
  );
};

export default App;

現在使用している教材と学習時間:本日の学習時間2.5時間

Udemy:MERN Stack Front To Back: Full Stack React, Redux & Node.js by Brad Traversy

★Section9:Dashboard & Profile Management

-Lec 48 Create Profile Action

-Lec 49 Edit Profile (このブログに書いた内容。本日はここまで完了)

進捗状況:68%

学習時間2.5時間

~本日は休みにしている教材~

Udemy:The Complete Web Developer: Zero to Mastery by Andrei Neagoie

進捗状況: 92%

★参考にした本★

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

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

★参照記事★

Quiita参照記事⇒react-routerのページ遷移をhandleで行う時にはwithRouterを使う

関連キーワード
  • 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コマンドではまったところと解決方法
おすすめの記事
97日目:Redux概要を復習&Redux devtools extension動く& Auth ReducerとRegister Action作成
プログラミング100日チャレンジ記録 #100daysofcode
昨日色々と上手くいかなかったので、本日は復習のみで終わるかと思ったのですが、ユーザーauthenticationのセクションを進めることがで...