快速搭建成熟的react项目

想要搭建react首先要安装node和npm.

1,建立一个名字为react的文件夹

2,在此文件夹下 输入命令 

npm init

生成package.json文件,此时的package.json中只有基础配置,想要项目运行还需要配置多种开发包

这是我上一个项目所用到的各种依赖,可以参考

{
  "name": "text",
  "version": "1.0.0",
  "description": "测试react",
  "main": "index.js",
  "scripts": {  
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "node server.js",
    "hot": "node server.hot.js",
    "dist": "webpack --config webpack.config.dist.js --progress --colors --watch -p"
  },
  "author": "",  
  "license": "ISC",
  "dependencies": {  
    "antd": "^2.13.11",
    "axios": "^0.17.1",
    "console-polyfill": "^0.3.0",
    "core-js": "^2.5.1",
    "es5-shim": "^4.5.9",
    "es6-promise": "^4.1.1",
    "fetch-ie8": "^1.5.0",
    "highcharts": "^6.0.4",
    "jquery": "^3.3.1",
    "moment": "^2.20.1",
    "msr": "^1.3.4",
    "react": "^15.6.2",
    "react-addons-css-transition-group": "^15.6.2",
    "react-bmap": "^1.0.69",
    "react-dom": "^15.6.2",
    "react-highcharts": "^16.0.1",
    "react-redux": "^4.4.5",
    "react-router": "^2.8.1",
    "redux": "^3.6.0",
    "redux-thunk": "^2.1.0",
    "video.js": "^6.7.3",
    "videojs-contrib-hls": "^5.14.0",
    "videojs-flash": "^2.1.0",
    "videojs-thumbnails": "^1.0.3"
  },
  "devDependencies": {   
    "autoprefixer-loader": "^3.2.0",
    "babel-core": "^6.18.2",
    "babel-helpers": "^6.24.1",
    "babel-loader": "^6.2.8",
    "babel-plugin-import": "^1.6.2",
    "babel-plugin-transform-class-properties": "^6.23.0",
    "babel-plugin-transform-decorators-legacy": "^1.3.4",
    "babel-polyfill": "^6.26.0",
    "babel-preset-env": "^1.6.1",
    "babel-preset-es2015": "^6.6.0",
    "babel-preset-react": "^6.5.0",
    "babel-preset-react-hmre": "^1.1.1",
    "babel-preset-stage-0": "^6.16.0",
    "body-parser": "^1.15.1",
    "clean-webpack-plugin": "^0.1.18",
    "css-loader": "^0.23.1",
    "express": "^4.14.0",
    "extract-text-webpack-plugin": "^1.0.1",
    "file-loader": "^0.8.5",
    "html-webpack-plugin": "^2.22.0",
    "http-proxy-middleware": "^0.17.3",
    "json-loader": "^0.5.7",
    "jsx-loader": "^0.13.2",
    "less": "^2.6.1",
    "less-loader": "^2.2.3",
    "node-sass": "^3.11.3",
    "react-hot-loader": "^1.3.1",
    "react-transform-catch-errors": "^1.0.2",
    "react-transform-hmr": "^1.0.4",
    "redbox-react": "^1.3.3",
    "redux-devtools": "^3.4.1",
    "sass": "^0.5.0",
    "sass-loader": "^4.0.2",
    "style-loader": "^0.13.1",
    "url-loader": "^0.5.7",
    "webpack": "^1.13.0",
    "webpack-dev-middleware": "^1.8.4",
    "webpack-dev-server": "1.14.1",
    "webpack-hot-middleware": "^2.20.0"
  }
}

 

其中的script是命令优化

正常情况下 执行打包命令会输入

webpack --config webpack.config.dist.js

使用命令优化 就可以直接输入

npm run dist

代替

此时仅仅将各种依赖命令给出 并没有下载,若想项目运行 需要先下载这些包,执行命令

npm install

到现在为止 仅仅将项目的依赖安装完成,

package.json文件包含了react项目中使用的大多数依赖,但是对于你的项目还需要具体问题具体分析

下载完成后会自动生成node_modules文件夹,里面为我们所需的依赖

3 在文件夹下新建各种文件

这些都是一个react项目所需的基本文件

src中包含页面 路由 模板和jsx

.babelrc是babel文件,babel是用最新标准编写的js代码向下编译成随处可用的版本.

通俗的将 就是通过babel将我们编译的ES6,ES7等代码转为ES5 ,转换编译

.babelrc

{
  "presets": [
    "stage-0",
    "es2015",
    "react"
  ],
  "plugins": [
      "transform-decorators-legacy",
      "transform-class-properties",
      ["import", {
        "libraryName": "antd",
        "style": "css"
      }]
  ]
}

在根目录下建index.html文件  添加html标签<div id="app"></div>

index.html文件

<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=EDGE" />
  <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
  <meta name="format-detection" content="telephone=no">
  <meta name="full-screen" content="yes">
  <meta name="x5-fullscreen" content="true">
  <title>测试页面</title>
<link href="/dist/app.css?28dc475d0ddb7ffb1324" rel="stylesheet"></head>
<body>
  <div id="root" style="position: relative;height: 100%;min-width: 1024px;"></div>

  <script>
    // 全局对象
    var babelHelpers = {
      typeof: function () {
        return "undefined";
      }
    };
  </script>
<script type="text/javascript" src="/project/dist/app.js?28dc475d0ddb7ffb1324"></script></body>
</html>

server.hot.js文件是热替换时的配置 在其中引入了webpack.config.hot.js文件

server.hot.js如下:

var webpack = require('webpack');
var express = require('express');
var config = require('./webpack.config.hot');
var proxyMiddleware = require('http-proxy-middleware')

var app = express();
var compiler = webpack(config);

app.use(require('webpack-dev-middleware')(compiler, {
	publicPath: config.output.publicPath,
	hot: true,
	historyApiFallback: true,
	inline: true,
	progress: true,
	stats: {
		colors: true,
	}
}));
app.use(require('webpack-hot-middleware')(compiler));

//将其他路由,全部返回index.html
app.get('*', function (req, res) {
	res.sendFile(__dirname + '/index.html')
});

app.listen(8000, function () {
	console.log('正常打开8000端口')
});

webpack.config.hot.js文件如下:

var babelPolyfill = require("babel-polyfill");
var path = require('path');
var webpack = require('webpack');
var ExtractTextPlugin = require('extract-text-webpack-plugin'); //css单独打包
var HtmlWebpackPlugin = require('html-webpack-plugin'); //生成html

//定义地址
var ROOT_PATH = path.resolve(__dirname);
var APP_PATH = path.resolve(ROOT_PATH, 'src'); //__dirname 中的src目录,以此类推
var APP_FILE = path.resolve(APP_PATH, 'APP.jsx'); //根目录文件app.jsx地址
var BUILD_PATH = path.resolve(ROOT_PATH, '/project/dist'); //发布文件所存放的目录


module.exports = {
    devtool: 'cheap-module-eval-source-map',
    entry: {
        app: [
            'babel-polyfill',
            'webpack-hot-middleware/client',
            APP_FILE
        ]
    },
    output: {
        publicPath: '/project/dist/', //编译好的文件,在服务器的路径,这是静态资源引用路径
        path: BUILD_PATH, //发布文件地址
        filename: '[name].js', //编译后的文件名字
        chunkFilename: '[name].[chunkhash:5].min.js',
    },
    module: {
        loaders: [{
            test: /\.js$/,
            exclude: /^node_modules$/,
            loaders: ['react-hot', 'babel'],
            include: [APP_PATH]
        }, {
            test: /\.css$/,
            // exclude: /^node_modules$/,
            loaders: ['style', 'css', 'autoprefixer'],
            // include: [APP_PATH]
        }, {
            test: /\.less$/,
            exclude: /^node_modules$/,
            loaders: ['style', 'css', 'autoprefixer', 'less'],
            include: [APP_PATH]
        }, {
            test: /\.scss$/,
            exclude: /^node_modules$/,
            loader: 'style-loader!css-loader!autoprefixer-loader!sass-loader',
            include: [APP_PATH]
        }, {
            test: /\.(eot|woff|svg|ttf|woff2|gif|appcache|swf)(\?|$)/,
            // exclude: /^node_modules$/,
            loader: 'file-loader?name=[name].[ext]',
            // include: [APP_PATH]
        }, {
            test: /\.(png|jpg|gif)$/,
            exclude: /^node_modules$/,
            loader: 'url-loader?limit=8192&name=images/[hash:8].[name].[ext]',
            //注意后面那个limit的参数,当你图片大小小于这个限制的时候,会自动启用base64编码图片
            include: [APP_PATH]
        }, {
            test: /\.jsx$/,
            exclude: /^node_modules$/,
            loaders: ['react-hot', 'jsx', 'babel'],
            include: [APP_PATH]
        }, {
            test: /\.json$/,
            loader: 'json-loader'
        }]
    },
    plugins: [
        new webpack.DefinePlugin({
            //process.argv:当前进程的命令行参数数组。
            //process.env:指向当前shell的环境变量,比如process.env.HOME。
            'process.env': {
                NODE_ENV: JSON.stringify('development') //定义编译环境
            }
        }),
        new HtmlWebpackPlugin({  //根据模板插入css/js等生成最终HTML
            filename: '../index.html', //生成的html存放路径,相对于 path
            template: './src/template/index.html', //html模板路径
            hash: false,
        }),
        new webpack.HotModuleReplacementPlugin(),
        new webpack.NoErrorsPlugin()
    ],
    resolve: {
        extensions: ['', '.js', '.jsx', '.less', '.scss', '.css'], //后缀名自动补全
        alias: { // 文件路径别名设置
            template: path.join(__dirname, 'src/template'),
            // style: path.join(__dirname, 'src/style'),
            router: path.join(__dirname, 'src/router'),
            reduxFile: path.join(__dirname, 'src/redux'),
            // images: path.join(__dirname, 'src/images'),
            // plugin: path.join(__dirname, 'src/plugin'),
            pages: path.join(__dirname, 'src/pages'),
            // component: path.join(__dirname, 'src/component'),
        }
    }
};

 此时配置已经基本完成

剩下src里面的

我在这里建立了3个页面 即pages里面的home,sign和title

先不管pages

4,先看redux

包含action,reducer和store

action是把数据从应用传递到store的有效荷载,是store数据的唯一来源

action中必须有一个字符串类型的type字段来表示要执行的动作.

以下为action的index.js


export const RECEIVE_MSG = 'RECEIVE_MSG';
export const receiveMsg = (userMsg) => ({
  type: RECEIVE_MSG, userMsg
});

export const postMsg = () => {
  return (dispatch) => {
      var userMsg={
        userName:"小明",
        age:"18"
      }
    dispatch(receiveMsg(userMsg));
  }
}

reducer为纯函数 接收旧的state和action返回新的state

也就是说 同样的输入,必定会得到同样的输出

纯函数是函数式编程,必须遵循一些约束

1不能改变参数

2不能调用系统的API

3不能调用不纯的方法,即每次会得到不同结果的方法,如Data.now(),

reducer的index.js文件如下

import * as actions from '../action/index';
export const userMsg=(state={
    userName:'',
    age:''
},action)=>{
    switch (action.type){
         case actions.RECEIVE_MSG:{
             return Object.assign({},state,{
                 userName:action.userMsg.userName,
                 age:action.userMsg.age
             })
         }
         default:{
             return state
         }
    }
}

首先引入action文件夹下所有的action(此例中只有一个)用actions表示  

定义一个函数,此函数接收一个RECERVE_MSG的行为,接收参数,返回新的state

store是保存数据的地方,可以看成一个容器,值得注意的是一个应用中只能有一个store,包含所有的数据

store中index.js代码如下

import {createStore,combineReducers,applyMiddleware,compose} from 'redux';
import * as reducer from '../reducer/index';
import thunk from 'redux-thunk';
var store;
if(!(window.__REDUX_DEVTOOLS_EXTENSION__ || window.__REDUX_DEVTOOLS_EXTENSION__)){
   store = createStore(
        combineReducers(reducer),
        applyMiddleware(thunk)
    );
}else{
    store = createStore(
        combineReducers(reducer),
        compose(applyMiddleware(thunk),window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()) //插件调试,未安装会报错
    );
}

export default store;

 创建store,引入reducer 引入插件,判断浏览器是否安装了reduxDevTool,如果安转了则启用compose插件,未安装使用applyMiddleware,

至此,redux部分完成

5.pages 页面

我在这里建了3个页面home sign和title页面

首先看home页面

import React, { Component } from 'react';
import { hashHistory } from "react-router";
import { connect } from 'react-redux';
import {postMsg} from "reduxFile/action";

class Home extends React.Component {
  constructor(props) {
    super(props);
    this.handleJumpLink=this.handleJumpLink.bind(this);
  }
  // 挂载
  componentDidMount() {
  
  }
  // 接受数据
  componentWillReceiveProps(nextProps) {

  }
  /**
   * 跳转路由
   * pathname  state  query
   */
  handleJumpLink(pathname,state,query){
    hashHistory.push({
        pathname,state,query
    })
  }
  getUserMsg(){
    this.props.postMsg();
  }
  // 渲染
  render() {
    return (
     <div>helloworld 
        <h1 onClick={e=>{this.handleJumpLink("/title",{},{})}}>这是标题</h1>
        <h2 onClick={e=>{this.handleJumpLink("/sign",{},{})}}>这是签名</h2>
        <div>姓名:{this.props.userMsg.userName}</div>
        <div>年龄:{this.props.userMsg.age}</div>
        <button onClick={e=>{this.getUserMsg.bind(this)()}}>获取用户信息</button>
     </div>

    );
  }
}

// state 到 props 映射
const mapStateToProps = (state) => {
  return {
    userMsg:state.userMsg
  }
}
//UI组件的参数到state.dispatch方法映射
const mapDispatchToProps = (dispatch, ownPorps) => {
  return {
    postMsg:()=>{
      dispatch(postMsg());
    },
  }
}
// redux 与组件连接
const HomeComponent = connect(
  mapStateToProps,
  mapDispatchToProps
)(Home);

export default HomeComponent;

首先引入所需的各种依赖

然后引入我们之前写的action 即获取用户信息的 postMsg

新建home组件

render里面渲染页面元素

点击获取信息,发射dispatch获取到信息,并保存在props中

sign页面

import React, { Component } from 'react';
import { hashHistory } from "react-router";
import { connect } from 'react-redux';

class Sign extends React.Component{
    constructor(props){
        super(props);
    }
    render(){
        return (
            <div>这是签名页面</div>
        )
    }
}
// state 到 props 映射
const mapStateToProps = (state) => {
    return {
    }
  }
  //UI组件的参数到state.dispatch方法映射
  const mapDispatchToProps = (dispatch, ownPorps) => {
    return {     
    }
  }
const SignComponent=connect(
    mapStateToProps,
    mapDispatchToProps
)(Sign);

export default SignComponent;

title页面

import React, { Component } from 'react';
import { hashHistory } from "react-router";
import { connect } from 'react-redux';

class Title extends React.Component {
  constructor(props) {
    super(props);
    this.handleJumpLink=this.handleJumpLink.bind(this);
  }
  // 挂载
  componentDidMount() {
  }
  // 接受数据
  componentWillReceiveProps(nextProps) {
  }
  handleJumpLink(pathname,state,query){
    hashHistory.push({
        pathname,state,query
    })
  }
  // 渲染
  render() {
    return (
     <div>
        这是标题页面
        <h1 onClick={()=>{
          this.handleJumpLink("/sign",{},{})
        }}>去签名页面</h1>
     </div>
    );
  }
}

// state 到 props 映射
const mapStateToProps = (state) => {
  return {
  }
}
//UI组件的参数到state.dispatch方法映射
const mapDispatchToProps = (dispatch, ownPorps) => {
  return {
  }
}
// redux 与组件连接
const TitleComponent = connect(
  mapStateToProps,
  mapDispatchToProps
)(Title);

export default TitleComponent;

6.页面建立好了 接下来就是关键的router了

先看代码

import React, { Component } from 'react';
import { Router, Route, IndexRoute, hashHistory } from 'react-router';
import { connect } from 'react-redux';

const history = hashHistory; // 路由方式

// root
class Roots extends Component{
  constructor(props){
    super(props);  
  }
  render () {
      return(
        <div>
            {this.props.children}
        </div>
      )
    } 
}
// state 到 props 映射
const mapStateToProps = (state) => {
  return {

  }
}
//UI组件的参数到state.dispatch方法映射
const mapDispatchToProps = (dispatch, ownPorps) => {
  return {
   
  }
}
// redux 与组件连接
const Root = connect(
  mapStateToProps,
  mapDispatchToProps,
)(Roots);


const home = (location, callback) => {
    require.ensure([], require => {
      callback(null, require('pages/home').default)
    },'home')
};
// 标题页面
const title = (location, callback) => {
    require.ensure([], require => {
      callback(null, require('pages/title').default)
    },'title')
}

// 签名页面
const sign = (location, callback) => {
    require.ensure([], require => {
      callback(null, require('pages/sign').default)
    },'sign')
}

const RouteConfig = (
  <Router history={history}>
    <Route path='/' component={Root}>
    <IndexRoute getComponent={home}></IndexRoute>
    <Route path='home' getComponent={home}></Route>
    <Route path='title' getComponent={title}></Route>
    <Route path='sign' getComponent={sign}></Route>
    </Route>
  </Router>
);

export default RouteConfig;

先定义root组件 在引入各个页面

7.模板 template和app.jsp文件

先看template的index.html

<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=EDGE" />
  <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
  <meta name="format-detection" content="telephone=no">
  <meta name="full-screen" content="yes">
  <meta name="x5-fullscreen" content="true">
  <title>测试</title>
</head>

<body>
  <div id="root" style="position: relative;height: 100%;min-width: 1024px;"></div>
  <script>
    // 全局对象
    var babelHelpers = {
      typeof: function () {
        return "undefined";
      }
    };
  </script>
</body>

</html>

这是app.jsp

require('console-polyfill');
require('es6-promise');
require('fetch-ie8');
require('core-js/fn/object/assign');
import React , { Component, PropTypes } from 'react';
import ReactDOM, { render } from 'react-dom';
import { Provider } from 'react-redux';
import Route from 'router/index.js';
import store from 'reduxFile/store/index';


import moment from 'moment';
import 'moment/locale/zh-cn';
moment.locale('zh-cn');

let rootEle = document.getElementById('root');

ReactDOM.render(
  <Provider store={store}>
    {Route}
  </Provider>,
  rootEle
);

到现在一个react项目已经建立完成了

在终端输入 

npm run hot

运行成功 在浏览器输入localhost:8000  就可以看到我们的项目运行效果

点击获取信息 执行action行为 

点击标题 进入标题页

总体来说 就是

1.package.json文件 

2.安装各种依赖

3.babel文件

4 webpack文件

5 server文件

6 页面src 

   src里面包含 pages redux router template 和jsp文件

   

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值