apprendre de youtube
. 1**Introduction**
2. Project Setup-Serve index.html with Expressjs
mkdir reddice
cd reddice/
npm init -y
git init
npm install express@latest –save
npm install –save-dev babel-cli@latest
npm install –save-dev babel-preset-es2015 nodemon@latest
vi package.json
{
"name": "reddice",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"server": "nodemon --watch server --exec babel-node -- server/index.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"express": "^4.14.1"
},
"devDependencies": {
"babel-cli": "^6.22.2",
"babel-preset-es2015": "^6.22.0",
"nodemon": "^1.11.0"
}
}
vi index.js
import express from 'express';
import path from 'path';
let app = express();
app.get('/',(req,res) => {
res.sendFile(path.join(__dirname,'./index.html'));
// res.readFile(path.join(__dirname,'./index.html'));
});
app.listen(3001,()=> console.log('running on localhost:3001'));
vi index.html
<!DOCTYPE html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Red Dice</title>
<meta content="width=device-width,initial-scale=1" name="viewport" />
</head>
<body>
<h1>Hello 33world</h1>
</body>
</html>
vi .gitignore
.DS_Store
node_modules
vi .babelrc
{
"presets":["es2015"]
}
git add *
git commit -m “Initial”
3. Project Setup-Render react component
# npm install --save react react-dom
# npm install --save-dev webpack@1.14.0 webpack-dev-middleware
#npm install --save-dev babel-loader
#npm install --save-dev babel-preset-react
//务必当心webpack这个项目中是老版本,不然很多问题,
babel-cli要的,babel一定不能装
vi client/components/App.js
import React from 'react';
export default () =>{
return (<h1> Hello from react</h1>)
}
vi server/index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Red Dice</title>
<meta content="width=device-width,initial-scale=1" name="viewport" />
</head>
<body>
<div id="app"></div>
<script src="bundle.js"></script>
</body>
</html>
vi client/index.js
import React from 'react';
import {render} from 'react-dom';
import App from './components/App';
render(<App />,document.getElementById('app'));
vi webpack.config.dev.js
import path from 'path';
export default {
devtools:'eval-source-map',
entry: path.join(__dirname,'/client/index.js'),
output:{
path:'/'
},
module:{
loaders:[
{
test:/\.js$/,
include:path.join(__dirname,'client'),
exclude: [/node_modules/],
loaders:['babel']
}
]
},
resolve:{
extensions:['','.js'],
}
}
vi server/index.js
import express from 'express';
import path from 'path';
import webpack from 'webpack';
import webpackMiddleware from 'webpack-dev-middleware';
import webpackConfig from '../webpack.config.dev';
let app = express();
app.use(webpackMiddleware(webpack(webpackConfig)));
app.get('/*',(req,res) => {
res.sendFile(path.join(__dirname,'./index.html'));
// res.readFile(path.join(__dirname,'./index.html'));
});
app.listen(3001,()=> console.log('running on localhost:3001'));
cat client/components/App.js
import React from 'react';
import Greetings from './Greetings';
class App extends React.Component{
render(){
return(
<Greetings />
);
}
}
export default App;
cat client/components/Greetings.js
import React from 'react';
export default () =>
{
return(
<h1>Hi444</h1>
)
}
3.1notice:
ERROR in ./client/index.js
Module parse failed: /Users/duqn/Desktop/react/reddice/client/index.js Unexpected token (5:7)
You may need an appropriate loader to handle this file type.
的解决方案:
webpack.config.dev.js 里要配置,以认出相关
3.2notice2:
ERROR in Entry module not found: Error: Cannot resolve module ‘babel-node’ in /Users/duqn/Desktop/react/reddice
A: npm install –save-dev babel-loader
3.3notice3
ERROR in ./client/index.js
Module build failed: SyntaxError: Unexpected token (5:7)
3 | import App from './components/App';
4 |
5 | render(<App />,document.getElementById('app'));
A: npm install –save-dev babel-preset-react
.babelrc
{
"presets":["es2015",'react']
}
3.4.notice:
atom install in mac
from https://segmentfault.com/a/1190000005984309
sudo npm install eslint-config-airbnb eslint-plugin-import@latest eslint-plugin-jsx-a11y@latest eslint-plugin-react@latest eslint@latest -g
4. Project Setup-hot reloading setup
npm install –save-dev react-hot-loader webpack-hot-middleware webpack-Hot-Middleware
cat server/index.js
import express from 'express';
import path from 'path';
import webpack from 'webpack';
import webpackMiddleware from 'webpack-dev-middleware';
import webpackHotMiddleware from 'webpack-Hot-Middleware';
import webpackConfig from '../webpack.config.dev';
let app = express();
const compiler = webpack(webpackConfig);
app.use(webpackMiddleware(compiler,{
hot:true,
publicPath: webpackConfig.output.publicPath,
noInfo:true
}));
app.use(webpackHotMiddleware(webpack(compiler)));
app.get('/*',(req,res) => {
res.sendFile(path.join(__dirname,'./index.html'));
// res.readFile(path.join(__dirname,'./index.html'));
});
app.listen(3001,()=> console.log('running on localhost:3001'));
cat webpack.config.dev.js
import path from 'path';
import webpack from 'webpack';
export default {
devtools:'eval-source-map',
entry: [
'webpack-hot-middleware/client',
path.join(__dirname,'/client/index.js'),
],
output:{
path:'/',
publicPath:'/'
},
plugins:[
new webpack.NoErrorsPlugin(),
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.HotModuleReplacementPlugin()
],
module:{
loaders:[
{
test:/\.js$/,
include:path.join(__dirname,'client'),
exclude: [/node_modules/],
loaders:['react-hot','babel']
}
]
},
resolve:{
extensions:['','.js'],
}
}
5. Project Setup-React router and baseic navigation
npm install --save react-router
cat client/routes.js
import React from 'react';
import { Route, IndexRoute } from 'react-router';
import App from './components/App';
import Greetings from './components/Greetings';
import SignupPage from './components/signup/SignupPage';
export default(
<Route path="/" component={App} >
<IndexRoute component={Greetings} />
<Route path="signup" component={SignupPage} />
</Route>
);
cat client/index.js
import React from 'react';
import { render } from 'react-dom';
import {Router,browserHistory} from 'react-router';
import routes from './routes';
render(<Router history={browserHistory} routes ={routes} /> ,document.getElementById('app'));
cat client/components/App.js
import React from 'react';
import NavigationBar from './NavigationBar';
class App extends React.Component{
render(){
return(
<div className ="container">
<NavigationBar />
{this.props.children}
</div>
);
}
cat client/components/Greetings.js
import React from 'react';
class Greetings extends React.Component {
render() {
return (
<div className="jumbotron" >
<h1>Hi444</h1>
</div>
);
}
}
cat client/components/NavigationBar.js
import React from 'react';
import { Link } from 'react-router';
export default () => {
return (
<nav className="navbar navbar-default">
<div className="container-fluid">
<div className="navbar-header">
<Link to="/" className="navbar-brand" > Red Dice</Link>
</div>
<div className="collapse navbar-collapse">
<ul className="nav navbar-nav navbar-right">
<li><Link to="/signup"> Sign up</Link> </li>
</ul>
</div>
</div>
</nav>
);
};
cat client/components/signup/SignupPage.js
import React from 'react';
class SignupPage extends React.Component {
render() {
return (
<h1> Sign up page </h1>
);
}
}
export default SignupPage;
6.Sign up form and its state
notice: 测试页面输入password时,出现提示
Warning: SignupForm is changing an uncontrolled input of type text to be controlled. Input elements should not switch from uncontrolled to controlled (or vice versa). Decide between using a controlled or uncontrolled input element for the lifetime of the component. More info: https://fb.me/react-controlled-components
npm install lodash --save
cat client/components/signup/SignupForm.js
import React from 'react';
import timezones from '../../data/timezones';
import map from 'lodash/map';
class SignupForm extends React.Component {
constructor(props) {
super(props);
this.state = {
username: '',
password: '',
email: '',
timezone: '',
};
this.onChange = this.onChange.bind(this);
this.onSubmit = this.onSubmit.bind(this);
}
onChange(e) {
this.setState({ [e.target.name]: e.target.value });
}
onSubmit(e) {
e.preventDefault();
console.log(this.state);
}
render() {
const options = map(timezones, (val, key) =>
<option key={val} value={val}>{key}</option>
);
return (
<form onSubmit={this.onSubmit}>
<h1> join our community </h1>
<div className="form-group">
<label className="control-label">Username</label>
<input
value={this.state.username}
onChange={this.onChange}
type="text"
name="username"
className="form-control"
/>
</div>
<div className="form-group">
<label className="control-label">Email</label>
<input
value={this.state.email}
onChange={this.onChange}
type="text"
name="email"
className="form-control"
/>
</div>
<div className="form-group">
<label className="control-label">Password</label>
<input
value={this.state.password}
onChange={this.onChange}
type="password"
name="password"
className="form-control"
/>
</div>
<div className="form-group">
<label className="control-label">PasswordConfirmation</label>
<input
value={this.state.passwordConfirmation}
onChange={this.onChange}
type="password"
name="passwordConfirmation"
className="form-control"
/>
</div>
<div className="form-group">
<label className="control-label">Timezone</label>
<select
className="form-control"
name="timezone"
onChange={this.onChange}
value={this.state.timezone}
>
<option value="" disabled> Choose Your Timezone</option>
{options}
</select>
</div>
<div className="form-group">
<button className="btn btn-primary btn-lg">
Sign up
</button>
</div>
</form>
);
}
}
export default SignupForm;
cat client/data/timezones.js
export default {
"(GMT-11:00) Niue": "Pacific/Niue",
"(GMT+11:00) Kiritimati": "Pacific/Kiritimati"
}
git add *
git commit -m ‘sign up form and its state’
7. user sign up-make ajax request via redux thunk action
npm install --save axios
npm install --save redux react-redux redux-thunk
cat client/index.js
import React from 'react';
import { render } from 'react-dom';
import { Router,browserHistory} from 'react-router';
import { Porvider } from 'react-redux';
import thunk from 'redux-thunk';
import { createStore,applyMiddleware } from 'redux';
import routes from './routes';
const store = createStore(
(state ={}) => state,
applyMiddleware(thunk)
);
render(
<Provider store={store}>
<Router history={browserHistory} routes ={routes} />
</Provider>,document.getElementById('app'));
cat client/components/signup/SignupPage.js
import React from 'react';
import { connect } from 'react-redux';
import SignupForm from './SignupForm';
import { userSignupRequest } from '../../actions/signupActions';
class SignupPage extends React.Component {
render() {
const { userSignupRequest }= this.props;
return (
<div className="row">
<div className="col-md-4 col-md-offset-4">
<SignupForm userSignupRequest={userSignupRequest} />
</div>
</div>
);
}
}
SignupPage.propTypes = {
userSignupRequest: React.PropTypes.func.isRequired
}
export default connect(null, { userSignupRequest })(SignupPage);
cat client/actions/signupActions.js
import axios from 'axios';
export function userSignupRequest(userData){
return dispatch => {
return axios.post('/api/users',userData);
}
}
cat client/components/signup/SignupForm.js
import React from 'react';
// import axios from 'axios';
import map from 'lodash/map';
import timezones from '../../data/timezones';
class SignupForm extends React.Component {
constructor(props) {
super(props);
this.state = {
username: '',
password: '',
passwordConfirmation: '',
email: '',
timezone: '',
errors: {},
};
this.onChange = this.onChange.bind(this);
this.onSubmit = this.onSubmit.bind(this);
}
onChange(e) {
this.setState({ [e.target.name]: e.target.value });
}
onSubmit(e) {
e.preventDefault();
this.setState({ errors: {} });
// axios.post('/api/users', { user:this.state} );
this.props.userSignupRequest(this.state).then(
() => {},
({ data }) => this.setstate({ errors: data }),
);
}
render() {
const { errors } = this.state;
const options = map(timezones, (val, key) =>
<option key={val} value={val}>{key}</option>,
);
return (
<form onSubmit={this.onSubmit}>
<h1> join our community </h1>
<div className="form-group">
<label className="control-label">Username
<input
value={this.state.username}
onChange={this.onChange}
type="text"
name="username"
className="form-control"
/>
{errors.username &&
<span className="help-block">{errors.username}</span>
}
</label>
</div>
<div className="form-group">
<label className="control-label">Email
<input
value={this.state.email}
onChange={this.onChange}
type="text"
name="email"
className="form-control"
/>
</label>
</div>
<div className="form-group">
<label className="control-label">Password
<input
value={this.state.password}
onChange={this.onChange}
type="password"
name="password"
className="form-control"
/>
</label>
</div>
<div className="form-group">
<label className="control-label">PasswordConfirmation
<input
value={this.state.passwordConfirmation}
onChange={this.onChange}
type="password"
name="passwordConfirmation"
className="form-control"
/>
</label>
</div>
<div className="form-group">
<label className="control-label">Timezone
<select
className="form-control"
name="timezone"
onChange={this.onChange}
value={this.state.timezone}
>
<option value="" disabled> Choose Your Timezone</option>
{options}
</select>
</label>
</div>
<div className="form-group">
<button className="btn btn-primary btn-lg">
Sign up
</button>
</div>
</form>
);
}
}
SignupForm.propTypes = {
userSignupRequest: React.PropTypes.func.isRequired,
};
export default SignupForm;
git commit -m ‘user sign up-make ajax request via redux thunk action’
8. user signup-server-side Validation
9. 8
10. 8
11. 8
##**#**12. 8
**#**13. 8
#14. 8
#15. 8
#16. 8
#17. 8
#18. 8
#19. 8
#20. 8
#21. 8
#22. 8
#23. 8
#24. 8
#25. 8
#26. 8
#27. 8
#28. 8
29. 8
30. 8
31. 8
32. 8
33. 8
34. 8
35. 8
36. 8
37. 8
38. 8
39. 8
40. 8
41. 8
42.