美文网首页web前端程序员
react入门-React + webpack 开发单页面应用(

react入门-React + webpack 开发单页面应用(

作者: 侬姝沁儿 | 来源:发表于2018-09-26 00:49 被阅读13次

    2018.09.26终---
    注意:在现今前端的日常开发中需要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 i react-router-dom   # react 路由器的DOM绑定(必安装)
    npm i node-sass sass-loader axios    # 使用sass和axios请求方式(根据个人情况决定是否安装,本人使用sass和axios)
    
    1.3 自定义配置模式
    npm run eject # 此时默认的项目结构会发生较大变化,注意观察前后变化
    
    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                             # 开发目录
      ├── components                    # 组件
      ├── router                        # 路由
        ├── index.js                    # 路由配置入口js
      ├── style                         # 样式
        ├── index.scss                  # css样式主文件
      ├── tools                         # 自定义js工具包
        ├── http-request.js             # 自定义的js请求库
      ├── view                          # 单页面应用
        ├── home.jsx                    # 首页jsx组件
      ├── App.js                        # dom 挂载文件
      ├── index.js                      # 入口文件
      ├── registerServiceWorker.js      # 注册服务文件
    ├── package-lock.json               # 包锁定文件,不用管。
    ├── package.json                    # 配置文件,有些内容在此配置
    └──README.md                        # 说明文档,该文档非常丰富,建议由时间阅读
    

    会shell的可以执行我的快捷命令:

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

    二、配置config相关

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

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

    alias: {
      ...
      '@': path.join(__dirname, '..', 'src'), # 添加这段内容
    }
    
    2.2 配置项目支持 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 registerServiceWorker from './registerServiceWorker'
    // import HttpRequest from './tools/http-request.js'
    
    ReactDOM.render(<App />, document.getElementById('root'))
    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/view/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 '@/view/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 文件
    //$res: "/erjimulu/image/"; // 打包时用此路径
    $res: "/image/"; // 本地开发是用此路径
    body {
      margin: 0; padding: 0; font-family: sans-serif; font-size: 12px;
    }
    

    四、配置接口请求相关

    4.1 配置请求代理

    请求 cnodejs.org 提供的公用接口。接口文档查看,请点击 https://cnodejs.org/api
    打开 package.json 文件,在最下面加上:

    {
      ...
      "proxy": {
        "/api/v1": {
          "target": "https://cnodejs.org",
          "changeOrigin": true
        }
      }
    }
    
    注意:配置了代理之后,项目需要重启,才能生效 npm start
    
    4.2 配置 src/tools/http-request.js 文件
    // 全局请求插件 Axios
    import Axios from 'axios'
    
    var axios = Axios.create() // 实例化
    
    axios.defaults.baseURL = '/api/v1/' // 接口请求前缀
    axios.defaults.withCredentials = true // 是否跨域
    axios.defaults.responseType = 'json' // json
    // axios.defaults.transformResponse = [(data) => {
    //   return DataHandle.filterNull(data)
    // }] // `transformResponse` 在请求完成后响应传递给 then/catch 前,允许修改响应数据,函数必须return,function (data) { return data }
    // 添加响应拦截器
    axios.interceptors.response.use(function (response) { // 请求成功的回调
      return Promise.resolve(response.data)
    }, function (error) { // 请求失败的回调
      // if (error.response) { // 请求已发出,但服务器响应的状态码不在 2xx 范围内
      //   console.error(error)
      //   console.log('错误数据: ', error.response)
      // } else { // 在提出请求设置时发生的错误: Something happened in setting up the request that triggered an Error
      //   console.error('Error', error.message)
      // }
      return Promise.reject(error)
    })
    
    export default axios
    
    4.3 测试 http-request.js 是否正常,配置 src/view/home.jsx 文件
    import React, { Component } from 'react'
    import { Link } from 'react-router-dom' // 路由相关 props.match 等
    // import Axios from 'axios'
    import Axios from '@/tools/http-request.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.get('topics').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.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
    

    附2.react 生命周期图

    react-生命周期.jpg

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

    react-building.sh

    # react 快捷构建
    
    createReact () { # 创建 react 项目
      echo "正在查看 npm 是否全局安装 create-react-app ..."
      npm list --global create-react-app 2>/dev/null 1>/dev/null # 查看全局是否安装 npmReact=$(npm list --global create-react-app)
      if [ $? -ne 0 ]; then #
        echo -n "需要的包 create-react-app 不存在,需要全局安装(Y/n)"
        read isInstall
        if [ "$isInstall" == 'Y' -o "$isInstall" == 'y' -o -z "$isInstall" ]; then #
          sudo npm i -g create-react-app # npm下安装react环境
        else
          echo "停止"
          exit
        fi
      fi
      echo -n "请输入你的项目名(必须为英文):"
      read projectName
      create-react-app $projectName # 创建一个项目名为 $projectName 的react项目
      cd $projectName # 进入此项目
    }
    
    installNeedLibrary () { # 安装一些基本的第三方库 和 自定义配置模式
      echo -n "是否安装一些基本的第三方库(Y/n):"
      read isInstall
      if [ "$isInstall" == 'Y' -o "$isInstall" == 'y' -o -z "$isInstall" ]; then #
        npm i react-router-dom # react 路由器的DOM绑定(必安装)
        npm i node-sass sass-loader axios # 使用sass和axios请求方式
      fi
    }
    
    configRequiredDirectories () { # 配置所需目录
      echo -n "是否自定义配置模式(Y/n):"
      read isEject
      if [ "$isEject" == 'Y' -o "$isEject" == 'y' -o -z "$isEject" ]; then #
        echo y | npm run eject # 此时默认的项目结构会发生较大变化,注意观察前后变化
      fi
      echo -n "是否使用基本目录结构(Y/n):"
      read isUsed
      if [ "$isUsed" == 'Y' -o "$isUsed" == 'y' -o -z "$isUsed" ]; then #
        cd src && mkdir components view router style tools # 在src下,创建我们需要的文件夹
        rm -r App.css App.test.js index.css logo.svg # 删除App.css App.test.js index.css logo.svg等无用文件
        cd router && touch index.js && cd ../ # router => index.js
        cd style && touch index.scss && cd ../ # style => index.scss
        cd tools && touch http-request.js && cd ../ # tools => http-request.js
        cd view && touch home.jsx && cd ../ # view => home.jsx
        cat <<EOF >App.js
    import React, { Component } from 'react'
    import RouterView from './router/index.js'
    
    class App extends Component {
      render() {
        return (
          <RouterView></RouterView>
        )
      }
    }
    
    export default App
    EOF
    
        cat <<EOF >index.js
    import React from 'react'
    import ReactDOM from 'react-dom'
    import App from './App.js'
    import registerServiceWorker from './registerServiceWorker'
    // import HttpRequest from './tools/http-request.js'
    
    ReactDOM.render(<App />, document.getElementById('root'))
    registerServiceWorker()
    EOF
    
        cat <<EOF >router/index.js
    import React, { Component } from 'react'
    import { BrowserRouter as Router, Switch, Route } from 'react-router-dom'
    
    import Home from '../view/home.jsx'
    
    export default class App extends Component {
      render () {
        return (
          <Router basename="/">
            <Switch>
              <Route exact path='/' component={Home} />
            </Switch>
          </Router>
        )
      }
    }
    EOF
    
        cat <<EOF >view/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">
            首页
          </div>
        )
      }
    }
    EOF
    
        cd ../
        cd public && mkdir image js && cd ../
      fi
    }
    
    npm -v 2>/dev/null 1>/dev/null # 2>/dev/null 1>/dev/null 把输出内容丢到黑洞里
    if [ $? -ne 0 ]; then #
      echo "程序已停止: npm 尚未安装,请安装后再试"
      exit
    else
      createReact # 创建 react 项目
      echo "项目已经运行完毕,请您查看项目文件和运行结果,查看完毕后,再进行下面操作:"
      echo "------------------------------------------------------------------"
      ls
      echo "------------------------------------------------------------------"
      installNeedLibrary # 安装一些基本的第三方库
      configRequiredDirectories # 配置所需目录
      npm start # 运行项目(项目运行后,查看项目文件和运行结果,查看完毕后,再进行下面操作)
    fi
    
    sh react-building.sh # 就在当前目录新建一个react的项目
    

    相关文章

      网友评论

        本文标题:react入门-React + webpack 开发单页面应用(

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