React&Redux

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 [email protected] 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.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章