美文网首页
React开发-公司内部

React开发-公司内部

作者: 深圳A1照教练 | 来源:发表于2018-03-14 10:19 被阅读0次

    React开发

    一. Node.js开发环境的搭建及配置

    Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。

    1. 下载安装和配置

      1. 下载安装

        • 下载:http://nodejs.cn/download/

        • 安装成功后,打开CMD窗口,键入

          node -v

        • 如果提示Node命令不存在,请手动修改环境变量,将nodejs安装目录添加至path目录

      2. 包管理工具
        常用的有3种

        • npm Node自带,速度较慢
        • yarn 推荐使用,速度快。
        • cnpm 淘宝弄得
      3. 配置

        • 设置代理(NPM默认代理很卡,需设置为淘宝镜像)

          npm config set registry https://registry.npm.taobao.org

        • 安装yarn模块(强烈推荐),-g 表示全局模块

          npm install yarn -g

      4. 常用的命令

        • 安装模块

          npm install <模块名> <-g> <--save或者--save-dev>
          yarn add <模块名> <--save或者--save-dev>

        • 卸载模块

          npm uninstall <模块名> <-g>
          yarn remove <模块名>

    1. 开始使用Node
      1. 常见第一个Node项目

        在D盘创建一个文件夹webapp,通过命令行创建webapp项目

        D:\webapp>npm init -y

        项目创建成功后,目录中多出了一个package.json文件

      2. 配置文件package.json

        {
          "name": "webapp",
          "version": "1.0.0",
          "description": "",
          "main": "index.js",
          "scripts": {
            "test": "echo \"Error: no test specified\" && exit 1"
          },
          "keywords": [],
          "author": "",
          "license": "ISC"
        }
        
        • name:表示项目名称

        • version:版本号

        • description:描述

        • main:加载时的入口文件,当你把项目分享给别人引用时,就是别人导入的模块。

        • scripts:脚本。

          命令行键入 npm test 等同于键入 echo "Error: no test specified" && exit 1

        • dependencies:依赖的模块

        • devDependencies:开发环境依赖的模块

        • license:开源协议

        更多:http://blog.csdn.net/woxueliuyun/article/details/39294375

    二、React开发

    React是用于构建用户界面的 JavaScript 库。
    官网:https://doc.react-china.org/

    1. 构建第一个React项目

      1. 添加全局模块create-react-app(官方项目模板)

        npm install -g create-react-app

      2. 创建React项目,名为webapp

        D:>create-react-app webapp --scripts-version=react-scripts-ts

      3. 运行

        D:\webapp>yarn start

      运行成功后,浏览器会自动打开该项目。

    2. 简单分析官方的项目模板里的内容

      1. 目录结构

        • node_modules目录:存放的是项目依赖的模块(包括dependencies和devDependencies)
          • @type目录:typescript类型文件(有些模块源码不是用typescript写的,因此需要额外的添加类型文件)
          • script目录:带有script字眼的目录,通常是封装好的命令脚本。
          • 其它:引入的模块
        • public目录:静态文件或者图片。
          • html文件,React会通过Js代码将项目添加到id为root的div下
          • 可以新增一个css文件,进行全局样式的配置
        • src目录:我们的项目
          • 项目入口文件是index.tsx
          • registerServiceWorker.ts是端口服务配置文件(涉及到NodeJs的API)
        • package.json,NodeJs依赖关系配置文件
        • tsconfig.json,typescript配置文件
        • tslint.json,代码规范配置文件(暂时不敢用,要求很严格)
      2. package.json文件分析

        {
          "name": "webapp",
          "version": "0.1.0",
          "private": true,
          "dependencies": {
            "react": "^16.2.0",
            "react-dom": "^16.2.0",
            "react-scripts-ts": "2.13.0"
          },
          "scripts": {
            "start": "react-scripts-ts start",
            "build": "react-scripts-ts build",
            "test": "react-scripts-ts test --env=jsdom",
            "eject": "react-scripts-ts eject"
          },
          "devDependencies": {
            "@types/jest": "^22.2.0",
            "@types/node": "^9.4.7",
            "@types/react": "^16.0.40",
            "@types/react-dom": "^16.0.4",
            "typescript": "^2.7.2"
          }
        }
        
        1. dependencies:依赖了三个模块react和react-dom是必须的核心模块,react-scripts-ts是react封装的webpack脚本模块。
        2. devDependencies:主要是依赖了typescript模块,因为React源码是用flow(类似TypeScript)写的,因此需要添加Type类型支持。
        3. scripts:常用的几个脚本。可以通过 npm start执行。
      3. tsconfig.json文件分析

        {
          "compilerOptions": {
            "outDir": "build/dist",
            "module": "esnext",
            "target": "es5",
            "lib": ["es6", "dom"],
            "sourceMap": true,
            "allowJs": true,
            "jsx": "react",
            "moduleResolution": "node",
            "rootDir": "src",
            "forceConsistentCasingInFileNames": true,
            "noImplicitReturns": true,
            "noImplicitThis": true,
            "noImplicitAny": true,
            "strictNullChecks": true,
            "suppressImplicitAnyIndexErrors": true,
            "noUnusedLocals": true
          },
          "exclude": [
            "node_modules",
            "build",
            "scripts",
            "acceptance-tests",
            "webpack",
            "jest",
            "src/setupTests.ts"
          ]
        }
        

        关键的几个配置介绍

        1. outDir编译后的文件路径。
        2. module模块化方式,(commonjs等)
        3. target编译后的js版本
        4. lib开发所有的Js版本
        5. rootDir是ts项目的路径。
        6. exclude和include,包含或不包含的文件夹。
          其它的根据英文字面意思即可。
    3. 开始编写我们自己的代码
      开发一个如下图的网页,点击添加,会将内容追加到下面:
      [图片上传失败...(image-5e9ea2-1520993928646)]

      src目录下添加 APP.tsx ListComponent.tsx AddComponent.tsx

      APP.tsx

      import * as React from 'react';
      import AddComponent from "./AddComponent";
      import ListComponent from "./ListComponent";
      
      export default class App extends React.Component<any, { data: string[] }> {
          private _styles = {
              container: {
                  width: "100%",
                  height: "100%",
              }
          };
      
          constructor(prop:any,context){
              super(prop, context);
              this.state = {
                  data:[]
              }
          }
      
          render() {
              console.log("App render");
              return (
                  <div style={this._styles.container}>
                      <AddComponent add={(text) => this.setState({data:[...this.state.data,text]})}/>
                      <ListComponent data={this.state.data}/>
                  </div>
              );
          }
      }
      

      AddComponent.tsx

      import * as React from "react";
      
      export default class AddComponent extends React.Component<{ add(text): void; }, any> {
          private _height = "40px";
          private _currValue = "";
      
          private _styles= {
              container: {
                  width: "300px",
                  height: this._height,
                  display: "flex",
                  flexDirection: "row",
                  margin: "100px",
              },
              input: {
                  height: "100%",
                  flex: 1,
              },
              add: {
                  height: "100%",
                  padding: "0 10px",
                  margin: "5px 10px"
              }
          };
      
          render() {
              console.log("AddComponent render");
              return (
                  <div style={this._styles.container}>
                      <input
                          style={this._styles.input}
                          type="text"
                          placeholder="请输入要添加的内容"
                          onChange={(event) => this._currValue = event.target.value}/>
                      <input
                          style={this._styles.add}
                          type="button"
                          value="添加"
                          onClick={() => {
                              this.props.add(this._currValue);
                          }}/>
                  </div>
              );
          }
      }
      

      ListComponent.tsx

      import * as React from "react";
      
      export default class ListComponent extends React.Component<{ data: string[] }, any> {
          private _styles = {
              container: {
                  width: "100%",
                  flex: 1,
              },
          };
      
          render() {
              console.log("ListComponent render");
              return (
                  <ul style={this._styles.container}>
                      {
                          this.props.data.map((value, index, array) => {
                              return (
                                  <li>{"第" + index + "条记录," + value}</li>
                              );
                          })
                      }
                  </ul>
              );
          }
      }
      
      1. React实现了 JavaScript 中写 HTML , HTML 中写 JavaScript
        • JavaScript 中写 HTML ,是通过括号包裹的,可以写成如下:
        let element = (<div><div>)
        
        • HTML 中写 JavaScript ,是通过大括号包裹的,可以写成如下
        let element = (<div>{"你好"+"!"}<div>)
        
      2. React组件必须继承React.Component,HTML布局通过render方法返回。
      3. React动态的更新组件式通过setState方法执行的。
      4. React可以通过外部传入属性,如:ListComponent组件中的data参数,获取方式是:this.props.data。
      5. 样式文件直接使用JSON来写即可,通过style引入。

      React是单向数据流单页面组件,每次刷新都会调用render方法,手动刷新是通过调用setState方法。
      烦恼:

      1. 由于刷新组件只能通过setState进行,意味着只能在组件内部进行更新页面。
      2. 由于是单向数据流,因此无法修改父组件传过来的属性,但是有时候就是要修改。

      这时候数据绑定模块就出现了,主要有两种mobx和redux,redux虽然是主流,但是使用起来非常繁琐,Mobx是后起之秀,结合了redux的理念,操作简单,容易上手,网上也有相关的对比。

    4. Mobx的使用

      1. 项目引入Mobx模块
        修改package.json文件,在dependencies节点添加

            "mobx": "^3.6.1",
            "mobx-react": "^4.4.2",
        

        执行命令行安装

        yarn install
        2. 修改App.tsx和ListComponent.tsx文件

        import * as React from 'react';
        import AddComponent from "./AddComponent";
        import ListComponent, {appState} from "./ListComponent";
        
        export default class App extends React.Component<any, { data: string[] }> {
            private _styles = {
                container: {
                    width: "100%",
                    height: "100%",
                }
            };
        
            constructor(prop:any,context){
                super(prop, context);
                this.state = {
                    data:[]
                }
            }
        
            render() {
                console.log("App render");
                return (
                    <div style={this._styles.container}>
                        <AddComponent add={(text) => appState.add(text)}/>
                        <ListComponent/>
                    </div>
                );
            }
        }
        
        import * as React from "react";
        import {observer} from "mobx-react";
        import {observable} from "mobx";
        
        class AppState {
            @observable data: string[] = [];
        
            add(text:string){
                this.data = [...this.data, text];
            }
        }
        export const appState = new AppState();
        
        @observer
        export default class ListComponent extends React.Component<any, any> {
            private _styles = {
                container: {
                    width: "100%",
                    flex: 1,
                },
            };
        
            render() {
                console.log("ListComponent render");
                return (
                    <ul style={this._styles.container}>
                        {
                            appState.data.map((value, index, array) => {
                                return (
                                    <li>{"第" + index + "条记录," + value}</li>
                                );
                            })
                        }
                    </ul>
                );
            }
        }
        

        yarn start 运行即可

      2. 原理简单分析

        • observable 被观察者,mobx实时监测被观察者的变化,如果发生变化,就会通知observer更新。
        • observer 观察者,收到observable的更新通知后,observer会检查这个observable自己有没有在使用,如果在使用,就会更新(调用render方法)
    5. 单页面跳转必备-路由器 router
      官网:https://react-guide.github.io/react-router-cn/

      1. 项目引入react-router模块
        修改package.json, 在dependencieshe和节点添加

          "dependencies": {
            "history": "^4.6.2",
            "react-router-dom": "^4.2.2",
          },
          "devDependencies": {
            "@types/history": "^4.6.2",
            "@types/react-router-dom": "^4.2.2",
          }
        

        执行命令行安装

        yarn install

      2. 开始编写路由器
        修改APP.tsx

        import React from "react";
        import {Route, Router} from "react-router";
        import {createBrowserHistory} from "history";
        
        export const browserHistory = createBrowserHistory();
        
        export default class App extends React.Component{
            render(){
                return(
                    <div style={{width:"100%",height:"100%",display:"flex",flexDirection:"column"}}>
                        <ul>
                            {
                                ["nav1","nav2"].map((value, index, array)=>{
                                    return(
                                        <li onClick={()=>{
                                            if(index ===0){
                                                browserHistory.push("/first")
                                            }else if(index ===1){
                                                browserHistory.push("/second")
                                            }
                                        }}>{value}</li>
                                    );
                                })
                            }
                            <Router history={browserHistory}>
                                <div>
                                    <Route exact path="/" component={Home}/>
                                    <Route path="/first" component={First}/>
                                    <Route path="/second" component={Second}/>
                                </div>
                            </Router>
                        </ul>
                    </div>
                );
            }
        }
        class Home extends React.Component{
            render(){
                return(
                    <div>
                        Home界面
                    </div>
                );
            }
        }
        class First extends React.Component{
            render(){
                return(
                    <div>
                        First界面
                    </div>
                );
            }
        }
        class Second extends React.Component{
            render(){
                return(
                    <div>
                        Second界面
                    </div>
                );
            }
        }
        
        

        yarn start 运行即可

      3. 原理简单分析

        • 待定,未知。

    三、Webpack打包机

    官网:http://www.css88.com/doc/webpack/

    他可以轻松的处理 JavaScript 依赖关系和加载顺序,并按规则打包或压缩成指定格式。

    1. 原理介绍

      [图片上传失败...(image-91324f-1520993928646)]

      有了打包机:
      
      • 项目可以使用更高级的JS语法(ES6以上)。
      • 项目可以使用更牛逼的TS语法
      • 项目可以轻松的压缩成单js css文件
      • 项目可以编译成指定ES版本的JS语法(目前浏览器完美支持es5
      • 项目可以把HTML写进JS文件,在根据loader转换成HTML(React)
      • 很多很多。。。。只有你有对应loader。
    2. webpack语法的简单介绍
      可以在根目录新增一个webpack.config.js配置文件,通过webpack --config webpack.config.js 运行。

      const HtmlWebpackPlugin = require('html-webpack-plugin');
      const path = require('path');
      
      module.exports = {
          entry: './src/index.js',
          output: {
              filename: 'bundle.js',
              path: path.resolve(__dirname, 'dist')
          },
          module: {
              rules: [
                  {
                      test: /\.css$/,
                      use: [
                          'style-loader',
                          'css-loader'
                      ]
                  }
              ]
          },
          plugins: [
              new HtmlWebpackPlugin({
                  title: 'Output Management'
              })
          ],
      };
      
      1. entry:入口文件。
      2. output:输出路径
      3. rules:规则配置,上面例子中配置了 当发现css文件时的处理方式。
      4. plugins:插件,使用别人封装好的插件处理,比如发现html文件时使用的HtmlWebpackPlugin
    3. 第一个loader(less)
      该例子背景是重新创建一个react-app

      D:>create-react-app webapp --scripts-version=react-scripts-ts

      1. 修改package.json,增加两个dev依赖

        "less": "^3.0.1",
        "less-loader": "^4.0.6",

        执行 yarn install 安装

      2. 打开路径node_modules/react-scripts-ts 这是react封装好的webpack

      3. 打开scripts/build看看build过程中,是引用了那个webpack.config配置。

        const webpack = require('webpack');
        const config = require('../config/webpack.config.prod');
        
        function build(previousFileSizes) {
          console.log('Creating an optimized production build...');
        
          let compiler = webpack(config);
          ...省略...
        }
        
        

        由代码可知,build使用的config路径是"../config/webpack.config.prod"

      4. 打开这个webpack.config.prod文件,找到rules(打包规则)配置中关于css的解析,因为less本身属于css的范畴。

        {
            test: /\.css$/,
            loader: ExtractTextPlugin.extract(
              Object.assign(
                {
                  fallback: {
                    loader: require.resolve('style-loader'),
                    options: {
                      hmr: false,
                    },
                  },
                  use: [
                    {
                      loader: require.resolve('css-loader'),
                    },
                    {
                      loader: require.resolve('postcss-loader'),
                    },
                  ],
                },
              )
            ),
        },
        

        test:目前只支持css文件,所以需要增加对less文件的支持,

        test: /.(css|less)$/,

        loader:目前只用了postcss-loader-->css-loader-->style-loader 需要增加ls-loader支持

        loader: require.resolve('less-loader')

        修改后的配置

        {
            test: /\.(css|less)$/,
            loader: ExtractTextPlugin.extract(
              Object.assign(
                {
                  fallback: {
                    loader: require.resolve('style-loader'),
                    options: {
                      hmr: false,
                    },
                  },
                  use: [
                    {
                      loader: require.resolve('css-loader'),
                    },
                    {
                      loader: require.resolve('postcss-loader'),
                    },
                    {
                      loader: require.resolve('less-loader'),  
                    }
                  ],
                },
              )
            ),
        },
        

        同理,我们修改start脚本的配置(因为start脚本用的是另一个config)。

      测试是否配置成功

      1. 将原来的 App.css 修改为 App.less
      2. 修改App.tsx文件中的 import './App.css'; 修改为 import './App.less';
        运行即可。

    四、TypeScript简单介绍

    官网:https://www.tslang.cn/
    TypeScript是JavaScript的超集,它的存在并不是为了取代JavaScript,而是辅助JavaScript实现类型检查,直到ES支持强类型,TypeScript就是可以光荣退休了。
    未来:TypeScript不存在淘汰的问题,因为它采用的是JavaScript语法,他所做的仅仅是增加了强类型。
    比如:

    let a:string = "test";

    编译成ES6

    let a = "test";

    编译成ES5

    var a = "test";

    所有的强类型在编译成JavaScript后都会消失。

    TypeScript类型的定义

    基础数据类型

    • string 字符串
    • number 数字
    • object 对象
    • undefined 未定义
    • {} 对象 可以指定成员
    • any 任意对象,懒人专用,定义后,typescript下岗了。

    组合使用

    • {[key:string]:number} key为string value为number的对象

    第一种:

    interface IPerson{
        name:string;
    }
    
    interface IStudent extends IPerson{
        score?:string;
    }
    
    let student:Iprop;
    
    

    第二种

    type IStudent = {
        name:string;
        score?:string;
    } 
    
    let student:Iprop;
    
    

    第三种

    let student:{name:string;score?:string;};
    

    ? 表示这个属性可有可无 student.score===undefined || string

    四、辅助工具

    1. cmder(推荐)
      一款支持复制粘贴,支持linux命令的windows命令行工具,选用。
      相关文章 http://blog.csdn.net/wnma3mz/article/details/78268463
    2. WebStorm
      1. WebStorm 的破解
        下载地址:https://www.jetbrains.com/webstorm/
        license server http://idea.ibdyr.com
      2. WebStorm配置
        开发语言的选择 File | Settings | Languages & Frameworks | JavaScript 默认的开发语言是ES6 修改为React JSX即可。
    3. 其它开发工具
      • VSCode(免费) VS的压缩版本
      • VS
      • Notepad+ 或 记事本
      • Xcode

    五、其它

    1. 我的tsconfig配置文件

      {
        "compilerOptions": {
          "outDir": "build/dist",
          "module": "esnext",
          "target": "es5",
          "lib": ["esnext","dom"],
          "jsx": "react",
          "rootDir": "src",
          "forceConsistentCasingInFileNames": true,
          "noImplicitReturns": true,
          "suppressImplicitAnyIndexErrors": true,
          "removeComments": true,
          "preserveConstEnums": true,
          "moduleResolution": "node",
          "experimentalDecorators": true,
          "noImplicitAny": false,
          "allowSyntheticDefaultImports": true,
          "noUnusedParameters": false,
          "noUnusedLocals": false,
          "strictNullChecks": true,
          "noImplicitThis": true,
          "sourceMap": true,
          "allowJs": false,
          "allowUnreachableCode": true,
          "allowUnusedLabels": true,
          "checkJs": false,
          "baseUrl": "."
        },
        "exclude": [
          "node_modules",
          "build",
          "scripts",
          "acceptance-tests",
          "webpack",
          "jest",
          "src/setupTests.ts"
        ],
        "include": [
          "src"
        ],
        "compileOnSave": true
      }
      
      

      outDir:编译后 build/dist目录下会出现编译后的文件。
      module:模块化规范(commonjs等),好几种。
      target:编译后的es版本,通常就是es5,浏览器支持es5,es6没有普及。
      lib:开发过程中使用的es版本,看心情。
      jsx:react或者react-native,native是移动端混合APP开发用的。
      rootDir:项目所在位置。
      sourceMap:如果没有souceMap,浏览器出现的一堆压缩过后的Js文件,很难受。没法调试。
      其它有道词典走一波即可。

    2. React的编程思想

      • 响应式
      • 组件化
    3. React更新组件的算法
      倘若git采用的算法叫做逐行算法,那么React采用的算法是同行算法。

    相关文章

      网友评论

          本文标题:React开发-公司内部

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