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