美文网首页reactJs
搭建一个react app项目

搭建一个react app项目

作者: ElineC | 来源:发表于2017-08-08 10:08 被阅读0次

前言

使用react-router、webpack、redux一步步启动一个react app项目
项目github源码:https://github.com/chenshaomei/react-douban

初始化项目

1、首先创建一个空文件夹 react-douban,初始化package.json

$ npm init

2、package.json文件添加依赖

{
  "name": "react-douban",
  "version": "1.0.0",
  "description": "",
  "main": "main.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "browser-sync start --server --files **/*.css, **/*.html, **/*.js",
    "dev": "webpack-dev-server"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "babel-core": "^6.25.0",
    "babel-loader": "^7.1.1",
    "babel-preset-es2015": "^6.24.1",
    "babel-preset-react": "^6.24.1",
    "browser-sync": "^2.18.12",
    "css-loader": "^0.28.4",
    "react": "^15.6.1",
    "react-dom": "^15.6.1",
    "react-hot-loader": "^1.3.1",
    "react-router": "^4.1.1",
    "style-loader": "^0.18.2"
  },
  "dependencies": {
    "file-loader": "^0.11.2",
    "html-loader": "^0.4.5",
    "html-webpack-plugin": "^2.29.0",
    "isomorphic-fetch": "^2.2.1",
    "query-string": "^4.3.4",
    "react-redux": "^5.0.5",
    "react-router": "^2.8.1",
    "redux": "^3.7.2",
    "redux-logger": "^3.0.6",
    "redux-thunk": "^2.2.0",
    "url-loader": "^0.5.9",
    "webpack": "^3.2.0",
    "webpack-dev-server": "^2.5.1",
    "whatwg-fetch": "^2.0.3"
  }
}

3、运行命令下载依赖模块:

$ npm install

4、在react-douban工程内,创建以下目录:

image.png

5、在 index.html文件中添加以下代码

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no,minimal-ui">
        <title>react-project</title>
    </head>
    <body>
        <div id="app"></div> 
    </body>
</html>

6、在 .babelrc文件中添加以下代码

{
    presets: [['es2015'], ['react']]
}

配置webpack

1、全局安装

$ npm install webpack -g

2、配置webpack文件,webpack.config.js

var path = require('path');
var webpack = require('webpack');
var HtmlwebpackPlugin = require('html-webpack-plugin');


module.exports = {
    // 打包的入口文件
  entry: __dirname + '/app/main.js',
   // 打包输出文件夹以及文件名
  output: {
    path: __dirname+'/build' ,
    publicPath: '/',
    filename: 'bundle.js'
  },
   //启动的webpack server配置
  devServer: {
    contentBase: path.join(__dirname, "build"),  //以build为根目录提供文件
    historyApiFallback: true,
    hot: true,
    port:8092, //端口号
    inline: true,
    // api 代理转发 
    proxy:{
        "/api": {
            target: "http://api.douban.com/v2/",
            pathRewrite: {"^/api" : ""},
            changeOrigin: true
        }
    }
  },
  devtool: 'source-map',
  //引入模块时就不需要写后缀了,会自动补全
  resolve: {
      modules: [
          path.join(__dirname, "app"),
          "node_modules"
      ],
     extensions: ['.js', '.json', '.css', '.scss']
  },
  // 加载器,对模块的处理逻辑
  module: {
    loaders: [
       {test:/\.css$/, loader: 'style-loader!css-loader'},
       {
           test: /\.html?$/,
           loader: 'html-loader',
       },
       {test:/\.(png|jpe?g|gif|svg)(\?.*)?$/, loader: 'url-loader?limit=8192'},
       {test:/\.js$/, loader: 'react-hot-loader!babel-loader', exclude: /node_modules/},
    ]
  },
  //插件
  plugins: [
    // 自动生成 html
    new HtmlwebpackPlugin({
      template: __dirname + "/index.html" // 指向自己创建的index.html的位置
  }),
  new webpack.HotModuleReplacementPlugin()
  ]
};

react-router

1、在main.js文件中添加以下内容(入口文件)

iimport React from 'react';
import { render } from 'react-dom';
import { Router, browserHistory } from 'react-router';
import { Provider } from 'react-redux';
import configureStore from './stores';

// 引入store
const store = configureStore();

// 引入路由
import { routes } from './router';

// 引入全局css
import './css/base.css';

render(
    <Provider store = { store }>
    <Router history={browserHistory}>
        {
            routes
        }
    </Router>
    </Provider>
    , document.getElementById('app'));

2、在router.js文件中添加以下内容(路由文件)

import React from 'react';
import { Router, Route, browserHistory, IndexRoute, Redirect } from 'react-router';

// 引入pages组件
import App from './App';
import Index from './pages/Index';
import Home from './pages/Home';
import Login from './pages/Login';
import Details from './pages/Details';

// 定义路由
const routes = (
    <Route path="/" component={ App }>
        <IndexRoute component={ Index }/>
        <Route path="/" component={ Index }>
            <Route path="/home" component={ Home } />
            <Route path="/my" component={ Login } />
        </Route>
        <Route path="/details/:id" component={ Details } />
    </Route>
)

export { routes };

3、在App.js文件中添加以下内容(根组件)

import React from 'react';
import ReactDom from 'react-dom';

import Nav from './components/Nav/Nav';

export default React.createClass({
  render() {
    return <div>
      {this.props.children}
    </div>
  }
})

4、在pages/Index.js中添加以下内容
在Index组件下,渲染Home(首页) 和My(我的)页面 ,并且渲染两个页面有公共的导航组件(components/Nav/Nav

import React from 'react';
import ReactDom from 'react-dom';

import Nav from '../components/Nav/Nav';
import Home from './Home';
export default class Index extends React.Component{
    constructor(props){
        super(props);
        // nav data
        this.state = {
            navList: [
                {
                    path:'/home',
                    icon:require('../images/icons/home.png'),
                    txt:'首页'
                },
                {
                    path:'/my',
                    icon:require('../images/icons/my.png'),
                    txt:'我的'
                }
            ]
        }
    }
    render(){
        return <div>
            {this.props.children || <Home />}
            <Nav navList = { this.state.navList }/>
        </div>
    }
}

5、创建导航组件components/Nav/Nav.js

  • components/Nav/Nav.js中添加以下内容
    activeIndex 是导航选中的下标,设置显示高亮
import React from 'react';
import { Link } from 'react-router';

import './Nav.css';
export default class Nav extends React.Component{
    constructor(props){
        super(props);
    }

    render(){
        let activeIndex = 0;
        if(location.pathname !='/'){
            activeIndex = -1;
        }
        // nav data
        let navList = this.props.navList || [];

        return <div className="nav">

            <ul className="nav-ul">
            {
                navList.map((item,index)=>{

                    return  <li key={index}  ><Link to={item.path} className={index==activeIndex?'active':''} activeClassName="active"><i></i><span className="txt">{item.txt}</span></Link></li>
                })
            }
            </ul>
        </div>
    }
}
  • components/Nav/Nav.css中添加以下内容
.nav{
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    width: 100%;
    height: 49px;
}
.nav::before{
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    width: 100%;
    height: 1px;
    background: #ccc;
    -webkit-transform-origin:0 0;
    transform-origin:0 0;
    -webkit-transform:scaleY(0.5);
    transform:scaleY(0.5);
}
.nav-ul{
    display: -webkit-box; /* OLD - iOS 6-, Safari 3.1-6 */
    display: -webkit-flex; /* NEW - Chrome */
    display: flex;
    width: 100%;
    height: 100%;
    background: #fff;

    -webkit-box-pack: center;
    -webkit-box-align: center;
    justify-content: center;
    align-items: center
}
.nav-ul li{
    width: 0%;
    -webkit-box-flex: 1;
    -webkit-flex: 1;
    flex: 1;
}
.nav-ul li a{
    display: block;
    text-align: center;
}

.nav-ul li a span{
    display: block;
    color: #999;
    font-size: 12px;
}
.nav-ul li a i{
    display: block;
    width: 24px;
    height: 24px;
    margin: 0 auto;
}
.nav-ul li:nth-child(1) a i{
    background: url(../../images/icons/home.png) no-repeat top center;
    background-size: 100%;
}
.nav-ul li:nth-child(2) a i{
    background: url(../../images/icons/search.png) no-repeat top center;
    background-size: 100%;
}
.nav-ul li:nth-child(3) a i{
    background: url(../../images/icons/my.png) no-repeat top center;
    background-size: 100%;
}
.nav-ul li:nth-child(1) a.active i{
    background: url(../../images/icons/home-active.png) no-repeat top center;
    background-size: 100%;
}
.nav-ul li:nth-child(2) a.active i{
    background: url(../../images/icons/search-active.png) no-repeat top center;
    background-size: 100%;
}
.nav-ul li:nth-child(3) a.active i{
    background: url(../../images/icons/my-active.png) no-repeat top center;
    background-size: 100%;
}
.nav-ul li a.active span{
    color: #333;
}

redux

1、action

action:描述“发生了什么”
它是 store 数据的唯一来源。一般来说你会通过 store.dispatch() 将 action 传到 store

2、reducer

reducer:根据 action 更新 state

  • 创建reducer
    reducers/index.js文件中添加如下内容
import { combineReducers } from 'redux';
import home from './home'
//使用redux的combineReducers方法将所有reducer打包合并起来
const rootReducer = combineReducers({
  home
})
export default rootReducer

拆分 Reducer,一个reducer只负责一个页面的state;(例如home只负责管理首页的state更新),然后再使用reduxcombineReducers方法将所有reducer打包合并起来

3、store

Store 就是把actionreducer联系到一起的对象,Redux 应用只有一个单一的 store

  • 注册store
    stores/index.js文件中添加如下内容
// 注册store
import { createStore, applyMiddleware } from 'redux'
import thunk from 'redux-thunk'
import { createLogger } from 'redux-logger' // 利用redux-logger打印日志
import reducer from '../reducers'

// 调用日志打印方法
const loggerMiddleware = createLogger()
//applyMiddleware来自redux可以包装 store 的 dispatch
//thunk作用是使action创建函数可以返回一个function代替一个action对象
const createStoreWithMiddleware = applyMiddleware(
  thunk,
  loggerMiddleware
)(createStore)
export default function configureStore(initialState) {
  const store = createStoreWithMiddleware(reducer, initialState)
  //热替换选项
  if (module.hot) {
    // Enable Webpack hot module replacement for reducers
    module.hot.accept('../reducers', () => {
      const nextReducer = require('../reducers')

      store.replaceReducer(nextReducer)
    })
  }
  return store
}

相关文章

网友评论

    本文标题:搭建一个react app项目

    本文链接:https://www.haomeiwen.com/subject/unttrxtx.html