react入门-React + webpack 开发单页面应用(react快速上手教程)

2018.09.26终---2019.11.10更---
注意:在现今前端的日常开发中需要nodejs+npm环境和基本的计算机知识(如命令行)。详情参考:nodejsLinux命令大全。不知道的请先去学会,不然下面的内容有可能不适合你。会使用shell的高手,请直接去博文最低下的附件3。

一、创建项目、安装基本第三方库以及配置所需目录

1.1 创建项目
sudo npm i -g create-react-app # npm下安装react环境
create-react-app react-demo # 创建一个项目名为react-demo的react项目
cd react-demo # 进入此项目
npm start # 运行项目(项目运行后,查看项目文件和运行结果,查看完毕后,再进行下面操作)
1.2 自定义配置模式
npm run eject # 此时默认的项目结构会发生较大变化,注意观察前后变化
1.3 安装一些基本的第三方库
npm i react-router-dom   # react 路由器的DOM绑定(必安装)
npm i node-sass sass-loader axios es6-promise    # 使用sass和axios请求方式(根据个人情况决定是否安装,本人使用sass和axios)
1.4 配置所需目录

不会shell的,可以手动配置目录为以下结构:(主要配置public和src其他默认就好)

├── config                          # 配置文件夹
├── node_modules                    # node 依赖文件夹
  ├── ...                           # 各种npm的js库
├── public                          # 静态资源目录、入口文件目录
  ├── image                         # 静态图片存放
  ├── js                            # 本地js第三方库
  ├── favicon.ico                   # 浏览器标签栏图标
  ├── index.html                    # 入口 index.html 文件
  ├── manifest.json                 # 配置参数
├── scripts                         # npm 脚本文件夹
  ├── ...                           # 默认
├── src                             # 开发目录
  ├── api                           # 请求
    ├── index.js                    # 请求的js
  ├── components                    # 组件
  ├── config                        # 配置
    ├── index.js                    # 配置的js
  ├── router                        # 路由
    ├── index.js                    # 路由配置入口js
  ├── style                         # 样式
    ├── index.scss                  # css样式主文件
  ├── tools                         # 自定义js工具包
    ├── index.js                    # 自定义的js方法
  ├── views                         # 单页面应用
    ├── home.jsx                    # 首页jsx组件
  ├── App.js                        # dom 挂载文件
  ├── index.js                      # 入口文件
  ├── App.test.js                   # 测试文件
  ├── serviceWorker.js              # 注册服务文件,旧版本是registerServiceWorker.js
  ├── setupProxy.js                 # 配置代理
├── package-lock.json               # 包锁定文件,不用管。
├── package.json                    # 配置文件,有些内容在此配置
└──README.md                        # 说明文档,该文档非常丰富,建议由时间阅读

会shell的可以执行我的快捷命令,不会的请按照上面的自行手动构建:

# react-src-catalog-building.sh
# 新建文件 react-src-catalog-building.sh,内容如下:(以下内容可以通过命令行执行)
cd src && mkdir api components config views router style tools # 在src下,创建我们需要的文件夹
rm -r App.css index.css logo.svg # 删除App.css App.test.js index.css logo.svg等无用文件
cd api && touch index.js && cd ../ # api => index.js
cd config && touch index.js && cd ../ # config => index.js
cd router && touch index.js && cd ../ # router => index.js
cd style && touch index.scss && cd ../ # style => index.scss
cd tools && touch index.js && cd ../ # tools => indext.js
cd views && touch home.jsx && cd ../ # views => home.jsx
touch setupProxy.js
cd ../
# 运行shell文件 react-src-catalog-building
sh react-src-catalog-building.sh # 如果是通过命令行执行上面内容,则不需要执行该命令

二、配置config相关

2.1 配置支持 @ 文件映射 src 目录

在根目录下的/config/webpack.config.js 文件中,找到 alias 的配置:

注意:旧版是/config/webpack.config.dev.js 文件和 /config/webpack.config.prod.js 文件中,找到 alias 的配置

alias: {
  ...
  '@': path.join(__dirname, '..', 'src'), // 添加这段内容
}
2.2 配置项目支持 scss 文件

新版你可以跳过这一步,因为它自己已经做了scss的支持

在根目录下的 /config/webpack.config.dev.js 文件和 /config/webpack.config.prod.js 文件中,找到 module 的配置

module: {
  strictExportPresence: true,
  rules: [
    { test: /\.scss$/, loaders: ['style-loader', 'css-loader', 'sass-loader'],},    // 再rules这个数组中第一个位置,添加这段内容
    ...
    {
      // "oneOf" will traverse all following loaders until one will
      // match the requirements. When no loader matches it will fall
      // back to the "file" loader at the end of the loader list.
      oneOf: [
        ...
        {
          exclude: [/\.(js|jsx|mjs)$/, /\.html$/, /\.json$/],   # 改为 exclude: [/\.(js|jsx|mjs)$/, /\.html$/, /\.json$/, /.scss$/], // 增加 /.scss$/ 来使其支持sass
          loader: require.resolve('file-loader'),
          options: {
            name: 'static/media/[name].[hash:8].[ext]',
          },
        },
      ]
    }
  ],
  ...
}

三、配置src下各个文件

3.1 配置 src/index.js 文件
import React from 'react'
import ReactDOM from 'react-dom'
import './style/index.scss'
import App from './App.js'
import * as serviceWorker from './serviceWorker' // 注意:新版本此处与旧版不一致,以新版为主;旧版import registerServiceWorker from './registerServiceWorker'

ReactDOM.render(<App />, document.getElementById('root'))

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister() // 注意:新版本此处与旧版不一致,以新版为主;旧版registerServiceWorker()
3.2 配置 src/App.js 文件
import React, { Component } from 'react'
import RouterView from './router/index.js'

class App extends Component {
  render() {
    return (
      <RouterView></RouterView>
    )
  }
}

export default App
3.3配置 src/views/home.jsx 文件
import React, { Component } from 'react'

export default class Home extends Component {
  constructor (props) {
    super(props)
    this.state = {}
  }

  componentDidMount () {
  }

  render () {
    return (
      <div className="home">
        Home-首页
      </div>
    )
  }
}
3.4 配置 src/router/index.js 文件
import React, { Component } from 'react'
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom'

import Home from '@/views/home.jsx'

export default class App extends Component {
  render () {
    return (
      <Router basename="/">
        <Switch>
          <Route exact path='/' component={Home} />
        </Switch>
      </Router>
    )
  }
}
3.5 配置 src/style/index.scss 文件
// $static: "/erjimulu/image/"; // 打包时用此路径
$static: "/image/"; // 本地路径

body {
  margin: 0; padding: 0; font-family: sans-serif; font-size: 12px;
}
3.6配置src/config/index.js 文件
export default {
  projectName: '项目名称', // 项目名称
  title: '项目title',
  /**
   * @description api请求基础路径
   */
  baseUrl: {
    dev: '/api/v1', // 开发环境前缀
    pro: '/api/v1' // 生产环境前缀
  },
  /**
   * @description 是否自行存储token
   */
  isSaveCookie: true,
  /**
   * @description token在Cookie中存储的天数,默认1天
   */
  cookieExpires: 1,
  /**
   * @description 是否使用国际化,默认为false
   * 如果不使用,则需要在路由中给需要在菜单中展示的路由设置 meta: {title: 'xxx'} 用来在菜单中显示文字
   */
  useI18n: false,
  /**
   * @description 默认打开的首页的路由name值,默认为home
   */
  homeName: 'home',
  // ...
  // 其他
}

四、配置接口请求相关

4.1 配置请求代理

请求 cnodejs.org 提供的公用接口。接口文档查看,请点击 https://cnodejs.org/api

相关参考这里:Proxying API Requests in Development新版react16.6中 create-react-app升级版(webpack4.0) 配置http请求跨域问题

1)安装http-proxy-middleware管理包:http-proxy-middleware

npm install http-proxy-middleware --save
# or
yarn add http-proxy-middleware

2)在src/setupProxy.js文件,然后写入如下代码:

const proxy = require('http-proxy-middleware');

module.exports = function(app) {
  app.use(proxy('/api/v1', {
    target: 'https://cnodejs.org',
    changeOrigin: true
  }));
};

注意:配置了代理之后,项目需要重启,才能生效 npm start

4.2 配置 src/api/index.js 文件
// 全局请求插件 Axios
import Config from '@/config'
import Axios from 'axios' // 全局请求插件 Axios

var Promise = require('es6-promise').Promise
var axios = Axios.create() // 实例化

const baseUrl = process.env.NODE_ENV === 'development' ? Config.baseUrl.dev : Config.baseUrl.pro
axios.defaults.baseURL = baseUrl // 接口请求前缀
axios.defaults.withCredentials = true // 是否跨域
axios.defaults.responseType = 'json' // json

// 设置默认请求头
// axios.defaults.headers = {
//   "Content-Type": "application/json"
// }

// `transformResponse` 在请求完成后响应传递给 then/catch 前,允许修改响应数据,函数必须return,function (data) { return data }
// axios.defaults.transformResponse = [(data) => {
//   return data
// }]

// 添加响应拦截器
axios.interceptors.response.use(function (response) { // 请求成功的回调
  return Promise.resolve(response.data)
}, function (error) { // 请求失败的回调
  return Promise.reject(error)
})

axios.original = Axios // 接口请求前缀不一致时的预留

export default axios
4.3 测试 src/api/index.js 是否正常,配置 src/views/home.jsx 文件
import React, { Component } from 'react'
import { Link } from 'react-router-dom' // 路由相关 props.match 等
import Axios from '@/api/index.js'

export default class Home extends Component {
  constructor (props) {
    super(props) // this.props 用来接收父组件的传值 子组件给父组件传值:父组件把操作 state 的方法,通过属性的形式传递给子组件,子组件调用该操作方法
    this.state = {
      list: []
    } // 局部状态
  }

  // React 生命周期--------------------------------------------------------------
  componentDidMount () { // 挂载周期
    this.getTopics()
  }

  componentWillUnmount () { // 卸载周期
  }
  // React 生命周期--------------------------------------------------------------

  // 自定义方法-------------------------------------------------------------------
  getTopics () {
    return new Promise((resolve, reject) => {
      Axios({ method: 'get', url: 'topics', params: {} }).then((response) => {
        console.log(response)
        this.setState({list: response.data}) // 构造函数 setState 更新组件局部状态
        // this.setState((prevState, props) => { // 接收先前的状态作为第一个参数,将此次更新被应用时的props做为第二个参数
        //   return {
        //     ...
        //   }
        // }) // 函数形式
        resolve()
      }).catch((error) => {
        console.log(error)
        reject()
      })
    })
  }
  // 自定义方法-------------------------------------------------------------------

  render () { // render 函数,渲染 dom 结构
    console.log(this)
    let { list } = this.state
    let dom = null

    if (list.length !== 0) {
      let listDom = list.map((item, index, array) => {
        // console.log(item, index, array)
        return (
          <li key={index}><Link to={`/details/${item.id}`}> {index + 1} - {item.title} </Link></li>
        )
      })
      dom = (<div className='tipics-list'> <ul>{listDom}</ul> </div>)
    }
    return (
      <div className="home">
      首页 {dom}
      </div>
    )
  }
}

重新 npm start 运行后:

运行最终结果

至此一个基本的react项目已经搭建完毕,入门工作已经完成,接下来需要的就是学习react的语法了。请参考:react 中文文档

附1. 自定义的搭建react的快捷脚本

https://github.com/nongshuqiner/react-building-project-shell

附2.atom 相关 react 的第三方包的安装

注意:本人使用的是 atom 编辑器,开发 react 需要安装一些插件,这里做了一个shell简化你的插件安装,如果你是其他编辑器请跳过这部分。

新建文件 atom-react-package.sh,内容如下:

# atom安装插件: 找到atom包存放根路径(例如: Mac下是 cd ~/.atom/packages),git clone XXX 某个包后,cd XXX 进入包,然后npm install安装,cd ../ || echo "Error: atom 的 ${PWD##*/} 包,安装失败" 回到 atom 包存放的根路径

unameOut="$(uname -s)"
case "${unameOut}" in
    Linux*)     machine=Linux;;
    Darwin*)    machine=Mac;;
    CYGWIN*)    machine=Cygwin;;
    MINGW*)     machine=MinGw;;
    *)          machine="UNKNOWN:${unameOut}"
esac
echo ${machine}

if [ ${machine} == "Linux" ]; then # Linux
  atomPackagesPath="$HOME/.atom/packages"
elif [ ${machine} == "Mac" ]; then # Mac
  atomPackagesPath="$HOME/.atom/packages"
else
  atomPackagesPath="$HOME/.atom/packages"
fi

echo ${atomPackagesPath}
echo "------------------------------------------------------------------"

cd $atomPackagesPath && ls || echo "Error: ${atomPackagesPath} 没有找到那个文件或目录"
echo "------------------------------------------------------------------"


# React 相关 atom 包

# atom-react-autocomplete:自动完成组件名称和Project类型,用于项目中使用的任何组件
echo "安装 'atom-react-autocomplete' ..."
echo "git clone https://github.com/DavidWells/atom-react-autocomplete"
git clone https://github.com/DavidWells/atom-react-autocomplete
cd atom-react-autocomplete
npm install
echo "Success: atom 的 ${PWD##*/} 包,安装成功" && cd ../ || echo "Error: atom 的 ${PWD##*/} 包,安装失败"
echo "------------------------------------------------------------------"

# autocomplete-js-import: JS导入语句的自动完成+提供程序
echo "安装 'autocomplete-js-import' ..."
echo "git clone https://github.com/DanielGarcia-Carrillo/autocomplete-js-import"
git clone https://github.com/DanielGarcia-Carrillo/autocomplete-js-import
cd autocomplete-js-import
npm install
echo "Success: atom 的 ${PWD##*/} 包,安装成功" && cd ../ || echo "Error: atom 的 ${PWD##*/} 包,安装失败"
echo "------------------------------------------------------------------"

# language-babel: atom内开发react的核心插件
echo "安装 'language-babel' ..."
echo "git clone https://github.com/gandm/language-babel"
git clone https://github.com/gandm/language-babel
cd language-babel
npm install
echo "Success: atom 的 ${PWD##*/} 包,安装成功" && cd ../ || echo "Error: atom 的 ${PWD##*/} 包,安装失败"
echo "------------------------------------------------------------------"

# emmet-jsx-css-modules: React内的Emmet补全
echo "安装 'emmet-jsx-css-modules' ..."
echo "git clone https://github.com/ambethia/emmet-jsx-css-modules"
git clone https://github.com/ambethia/emmet-jsx-css-modules
cd emmet-jsx-css-modules
npm install
echo "Success: atom 的 ${PWD##*/} 包,安装成功" && cd ../ || echo "Error: atom 的 ${PWD##*/} 包,安装失败"
echo "------------------------------------------------------------------"

# language-javascript-jsx: JavaScript, ES6, ES7, React JSX, Flow支持
echo "安装 'language-javascript-jsx' ..."
echo "git clone https://github.com/subtleGradient/language-javascript-jsx"
git clone https://github.com/subtleGradient/language-javascript-jsx
cd language-javascript-jsx
npm install
echo "Success: atom 的 ${PWD##*/} 包,安装成功" && cd ../ || echo "Error: atom 的 ${PWD##*/} 包,安装失败"
echo "------------------------------------------------------------------"

# atom-react-snippets:atom的react代码片段补齐
echo "安装 'atom-react-snippets' ..."
echo "git clone https://github.com/webbushka/atom-react-snippets"
git clone https://github.com/webbushka/atom-react-snippets
cd atom-react-snippets
npm install
echo "Success: atom 的 ${PWD##*/} 包,安装成功" && cd ../ || echo "Error: atom 的 ${PWD##*/} 包,安装失败"
echo "------------------------------------------------------------------"

打开控制台执行(任何目录下执行都可以)

sh atom-react-package.sh # 注意:不支持window

附3.react 生命周期图

react-生命周期.jpg

结语

提示:后面还有精彩敬请期待,请大家关注我的专题:web前端。如有意见可以进行评论,每一条评论我都会认真对待。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,347评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,435评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,509评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,611评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,837评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,987评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,730评论 0 267
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,194评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,525评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,664评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,334评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,944评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,764评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,997评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,389评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,554评论 2 349

推荐阅读更多精彩内容

  • 1 Webpack 1.1 概念简介 1.1.1 WebPack是什么 1、一个打包工具 2、一个模块加载工具 3...
    Kevin_Junbaozi阅读 6,645评论 0 16
  • 版权声明:本文为博主原创文章,未经博主允许不得转载。 webpack介绍和使用 一、webpack介绍 1、由来 ...
    it筱竹阅读 11,060评论 0 21
  • GitChat技术杂谈 前言 本文较长,为了节省你的阅读时间,在文前列写作思路如下: 什么是 webpack,它要...
    萧玄辞阅读 12,679评论 7 110
  • 目录第1章 webpack简介 11.1 webpack是什么? 11.2 官网地址 21.3 为什么使用 web...
    lemonzoey阅读 1,731评论 0 1
  • 今天,咱们聊聊宇航员吧!苏联有一位宇航员第一个进入太空,有一次美国和苏联比赛看谁先登上月球,最后,美国赢了。还有一...
    超级安安007阅读 292评论 0 0