新しいファイル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を使う