美文网首页
react知识点

react知识点

作者: 栗子daisy | 来源:发表于2019-08-06 15:24 被阅读0次

    state-setState

    对象方式(对象合并方式 object.assigin())、函数方式 ( 队列 )

    1. 如何修改状态:不能用 this.state, 用 setState(setState 是异步批量执行的,如果
      同时操作多个 setState 一起执行效率高)
    2. setState 后如何获得更新的 state: 回调或钩子函数 componentDidUpdate 中
    3. 如何操作之前的 state:不建议从 this.state 里面获取 , 用函数方式更新 state 。
    // 回调
    this.setState({}, function() {
      // 回调中可以拿到state更新后的值
    });
    componentDidUpdate(){
      // 钩子函数可以获取state更新后的值
    }
    // 操作之前的state--实现每次加2
    this.setState((prevState, props) => ({
      // prevState可以拿到上一次更新后的state
      count: prevState.count + 1
    }));
    this.setState((prevState, props) => ({
      count: prevState.count + 1
    }));
    

    组件两种形态

    class function

    生命周期 16.0

    import React, { Component } from 'react';
    import PropTypes from 'prop-types';
    
    class Home extends Component {
      constructor(props) {
        super(props);
        this.state = {
          msg: props.prop
        };
        console.log('0 constructor');
      }
    
      componentWillMount() {
        // 组件将要挂载:可以访问属性和状态,进行api调用,但没办法进行dom操作
        console.log('1 componentWillMount组件将要挂载');
      }
    
      componentDidMount() {
        // 组件已经挂载,可进行状态更新操作
        console.log('2 componentDidMount组件已经挂载');
      }
    
      componentWillReceiveProps(nextProps) {
        // 组件属性更新:父组件传递的属性有变化
        console.log('3 componentWillReceiveProps组件属性更新');
        this.setState({
          msg: nextProps.prop
        });
      }
    
      shouldComponentUpdate(nextProps, nextState) {
        // 组件是否需要更新,返回布尔值
        console.log('4 shouldComponentUpdate组件是否需要更新');
        return false;
      }
    
      componentWillUpdate(nextProps, nextState) {
        // 组件将要更新
        console.log('5 componentWillUpdate组件将要更新');
      }
    
      componentDidUpdate(prevProps, prevState) {
        // 组件已经更新
        console.log('6 componentDidUpdate组件已经更新');
      }
    
      componentWillUnmount() {
        // 组件已经移除
        console.log('7 componentWillUnmount组件已经移除');
      }
    
      render() {
        console.log('render 组件渲染了');
        return (
          <div>
            state:{this.state.msg}
            props:{this.props.prop}
          </div>
        );
      }
    }
    
    Home.propTypes = {};
    
    export default Home;
    
    <Home prop={this.state.name} />;
    

    onClick 传参 onClick={this.handleClick(child)}错误,自动执行
    onClick={this.handleClick.bind(this,child)}或者
    onClick={()=>this.addtocart(child)}

    npm install react-router-dom The prop history is marked as required in
    Router, but its value is undefined.

    npm install redux react-redux

    组件交互

    组件化

    • UI=F(state)

    • 容器组件 VS 展示组件

      • class function
      • PureComponent : 定制了 shouldComponentUpdate 后的 Component( 浅比较 )
      • 解套:确保数据类型是值类型<Commenta key={i} {...c}/>
      • 如果是引用类型,确保地址不变,同时不应该有深层数据变化
    • 组件复合而非组件继承 {props.children}

    • 高阶组件 HOC 函数

    function Kai(props) {
      return (
        <div>
          {props.stage}-{props.name}
        </div>
      );
    }
    // 高阶组件
    const withName = Comp => {
      // 假设通过特殊手段获取名称
      return props => <Comp {...props} name="aaa" />;
    };
    export default withName(Kai);
    
    • 装饰器 -es7

      npm install --save-dev babel-plugin-transform-decorators-legacy

    // 添加装饰器能力
    config = injectBabelPlugin(
      ['@babel/plugin-proposal-decorators', { legacy: true }],
      config
    );
    
    • 组件库 antd- 表单设计思想

    npm install antd

    import Button from 'antd/lib/button';
    import 'antd/dist/antd.css';
    

    配置按需加载

    // 具名导入
    import { Button } from 'antd';
    

    npm install react-app-rewired@2.0.2-next.0 babel-plugin-import --save

    启动项目:

    // package.json
     "scripts": {
        "start": "react-app-rewired start",
        "build": "react-app-rewired build",
        "test": "react-app-rewired test --env=jsdom",
        "eject": "react-app-rewired eject"
      }
    // config-overrides.js
    const { injectBabelPlugin } = require('react-app-rewired');
    module.exports = function override(config, env) {
      // 按需加载
      config = injectBabelPlugin(
        ['import', { libraryName: 'antd', libraryDirectory: 'es', style: 'css' }],
        config
      );
      return config;
    };
    

    children

    children 是任意合法的 js 表达式,包括函数

    const api = {
      getUser: () => ({ name: 'jerry', age: 20 })
    };
    function Fetcher(props) {
      //props:{name: "getUser", children: ƒ}
      let user = api[props.name](); //user:{name: "jerry", age: 20}
      return props.children(user);
    }
    
    <Fetcher name="getUser">
      {({ name, age }) => (
        <p>
          {name}-{age}
        </p>
      )}
    </Fetcher>;
    
    function FilterP(props) {
      return (
        <div>
          {/* React.Children提供若干操作嵌套内容的帮助方法 */}
          {/* props.children处理的数组本身 */}
          {React.Children.map(props.children, child => {
            console.log('child', child); //vdom
            if (child.type != 'p') {
              //过滤非p标签
              return;
            }
            return child;
          })}
        </div>
      );
    }
    <FilterP>
      <a>aaaaaaaaaaaaa</a>
      <p>ppppppppppp11111111111</p>
      <h5>h5555555555</h5>
      <p>ppppppppppppp55555555555555</p>
      <div>dsffdivvv</div>
    </FilterP>;
    // child {$$typeof: Symbol(react.element), type: "a",...}
    
    function RadioGroup(props) {
      return (
        <div>
          {/* {
              //  Cannot add property name, object is not extensible对象不可扩展
            React.Children.forEach(props.children,child=>{
              child.props.name=props.name;
            })
          } */}
            {/* // 扩展后返回新的 */}
          {React.Children.map(props.children, child => {
            return React.cloneElement(child, { name: props.name });
          })}
        </div>
      );
    }
    function Radio({ children, ...rest }) {
      return (
        <label>
          <input type="radio" {...rest} />
          {children}
        </label>
      );
    }
    
     {/* 编辑children */}
    <RadioGroup name="mvvm">
      <Radio value="vue">vue</Radio>
      <Radio value="react">react</Radio>
      <Radio value="angular">angular</Radio>
    </RadioGroup>
    // <label><input type="radio" name="mvvm" value="vue">vue</label>
    

    jsx原理

    1.webpack+babel-loader 打包检测到jsx => React.createElement(...)

    1. React.createElement(...)执行结束会得到一个js对象树,能完整描述dom结构,称为虚拟DOM
    2. ReactDom.render(vdom,container)将vdom转换成dom追加到container中
      通过遍历vdom树
      kvdom转换dom

    虚拟dom

    bug

    无法正常显示

    var arr=["a","b","c"]
    arr.includes("a") //true
    var arr2=[{name:'aa',age:20},{name:'bb',age:30}]
    arr2.every(person=>person.age===20)
    //false
    arr2.find(person=>{return person.age===20})
    //{name: "aa", age: 20}
    arr2.some(person=>{return person.age===20})
    //true
    

    持久化

    react

    jsx redux RN React-Server

    npm install react

    npm install babel-core babel-preset-env babel-preset-react babel-loader
    babel-preset-stage-0 --save-dev 注意版本一致

    {
      test: /\.jsx?$/,
      // test: /\.(js|jsx)$/,
      exclude: '/node_modules',
      include: src,
      use: ['babel-loader?cacheDirectory'],
    }
    
    .babelrc
    {
      "presets": ["react", ["env", { "modules": false }]],
      "plugins": ["syntax-dynamic-import"]
    }
    

    happypack

    npm isntall happypack

     module: {
        //模块:放loader/插件
        rules: [
          {
            test: /\.jsx?$/,
            exclude: '/node_modules',
            use: 'happypack/loader?id=babel'
          }],
      },
      plugins: [
      new HtmlWebpackPlugin({
        new HappyPack({
          id: 'babel', // 上面loader?后面指定的id
          threadPool: happyThreadPool,
          use: ['babel-loader?cacheDirectory'],
          verbose: true
        })
      ],
    
    import React from 'react';
    import ReactDOM from 'react-dom';
    function loadIndex() {
      ReactDOM.render(<h1>hello world</h1>, document.getElementById('app'));
    }
    loadIndex();
    

    "scripts": {
      "build": "webpack --config build/webpack.pro.config.js"
    },
    

    uglifyjs-webpack-plugin

    const UglifyESPlugin = require('uglifyjs-webpack-plugin');
    plugins: [
      new UglifyESPlugin({
        uglifyOptions: {
          compress: {
            warnings: false,
            drop_console: true,
            collapse_vars: true,
            reduce_vars: true
          },
          output: {
            beautify: false,
            comments: false
          }
        }
      })
    ];
    

    tree shaking

    按需加载

    window.document.getElementById('btn').addEventListener('click', function() {
      import(/* webpackChunkName:"show" */ './show').then(show => {
        show('webpack');
      });
    });
    
    // show.js
    module.exports = function(content) {
      window.alert('hello' + content);
    };
    

    npm install babel-plugin-syntax-dynamic-import 识别 import

    function getAsyncComponent(load) {
      return class AsyncComponent extends PureComponent {
        componentDidMount() {
          load().then(({ default: component }) => {
            this.setState({
              component
            });
          });
        }
        render() {
          const { component } = this.state || {};
          return component ? createElement(component) : null;
        }
      };
    }
    function loadIndex() {
      ReactDOM.render(
        <HashRouter>
          <nav>
            <Link to="/">Home</Link>&nbsp;
            <Link to="/about">about</Link>
          </nav>
          <hr />
          <Route exact path="/" component={Home} />
          <Route
            path="/about"
            component={getAsyncComponent(() =>
              import(/* webpackChunkName: 'page-about' */ './views/about')
            )}
          />
        </HashRouter>,
        document.getElementById('app')
      );
    }
    loadIndex();
    

    antd form 组件开发,源码功能开发

    redux

    npm install redux --save npm install react-redux --save

    // index.js
    import { Provider } from 'react-redux';
    import store from './store'
     <Provider store={store}>
    </Provider>
    // store
    import {createStore} from 'redux'
    const counterReducer=(state=0,action)=>{// reducer: 状态修改具体执行者(state,action)->newState
        switch(action.type){
            case 'add':
            return state+1;
            case 'minus':
            return state-1;
            default:
            return state
        }
    }
    export default createStore(counterReducer)
    // reduxtest
    import React, { Component } from 'react';
    import { connect } from 'react-redux';
    class ReduxTest extends Component {
      constructor() {
        super();
      }
      render() {
        return (
          <div>
            {/* {store.getState()}
            <button onClick={()=>store.dispatch({type:'minus'})}>-</button>
            <button onClick={()=>store.dispatch({type:'add'})}>+</button> */}
            {this.props.num}
            <button onClick={() => this.props.minus()}>-</button>
            <button onClick={() => this.props.add()}>+</button>
          </div>
        );
      }
    }
    const mapStateToProps = state => ({ num: state });
    const mapDispatchToProps = dispatch => ({
      add: () => dispatch({ type: 'add' }),
      minus: () => dispatch({ type: 'minus' })
    });
    export default connect(mapStateToProps, mapDispatchToProps)(ReduxTest);
    

    redux中间件

    npm install redux-thunk redux-logger
    redux-thunk异步操作
    redux-logger日志记录

    react-router

    npm install react-router-dom

    核心三个 api 的实现

    setState 原理

    diff

    jsx( 面试问题三部曲 )

    1. 什么是 jsx? js 语法扩展,用类似 xml 描述视图模板
    2. 为什么需要 jsx?执行快,类型安全,提高开发效率
    3. 原理: webpack babel-loader 预编译 jsx 为
      React.CreateElement(type,props,...children)

    {typeof: Symbol(react.element), type: ƒ, key: null, ref: null, props: {…}, …}typeof:Symbol(react.element)
    key:null
    props:

    webpack.config.js

    const path=require('path')
    module.exports={
        mode:'development',//production
        entry:{//入口
            index:'./index.js'//单入口
             // main: './main.js' //多入口
        },
        output:{
            path:path.resolve(__dirname,'build'),//默认是dist
            filename:'bundle.min.js'//多入口'[name].min.js'
        },
         module: {
        //模块:放插件,loader
        //json [{test,use}]
        rules: [
          {
            test: /\.css$/,
            use: ['style-loader','css-loader']//从后往前
          },
    
          }
        ]
      }
    }
    

    webpack

    mode

    如果不写默认在生产模式,不好,所以报错 Set 'mode' option to 'development' or 'production' to enable defaults for eachenvironment.

    loader

    样式文件 loader

    import style from './index.css' <script type="text/javascript" src='./build/bundle.min.js'></script>

    css less

    npm install style-loader css-loader

    npm install less less-loader

    1. css-loader: css to js webpack 才识别,否则报错You may need an appropriate loader to handle this file type.
    2. style-loader: 插入页面生效<header><style type="text/css"></style></header>

    css 加上浏览器前缀

    npm install autoprefixer postcss-loader

    1. postcss-loader: css 浏览器兼容性 -webkit-transform, 需要配置文件
      postcss.config.js
    2. autoprefixer: 插件,css 加上浏览器前缀
    {
      test: /\.less$/,
      use: ['style-loader','css-loader','less-loader', 'postcss-loader']//从后往前
    },
    
    postcss.config.js
    const autoprefixer = require('autoprefixer');
    module.exports = {
      plugins: [
        //   插件,支持loader
        autoprefixer
      ]
    };
    

    图片文件 loader

    1. file-loader: 读取并输出文件

    npm install file-loader

     {
      test: /\.(jpg|gif|png)$/i,
      use: {
        loader:'file-loader',
        options:{
          outputpath:'images/'
      }
    },
    

    file-loader: You may need an appropriate loader to handle this file type.
    img/1.jpg------>build/images/0b7dcde232259cf01ef2db9d0584243d.jpg

    2. url-loader: 读取并输出 base64

    npm install url-loader

     {
      test: /\.(jpg|gif|png)$/i,
      use: {
        loader: 'url-loader',
        options: {
          outputPath: './images/',
          limit: 20 * 1024 //20k以下
        }
    }
    

    background-image:url(data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAMCAgMCAgMDAwMEAwME…6HX0JXlH7PHgDVPAvgu5uPEWw+J9evptW1RY33ok0)

    es6 文件 loader

    npm install babel-loader @babel/core @babel/preset-env

     {
      test: /\.jsx?$/,
      exclude: '/node_modules', // 排除
      use: {
        loader: 'babel-loader',
        options: {
          presets: ['@babel/preset-env']
        }
      }
    },
    

    webpack-dev-server: dev 环境启动服务

    npm install webpack webpack-cli webpack-dev-server -D

    1. webpack
    2. webpack-cli 启动 webpack-dev-server
    3. webpack-dev-server 直接启动不行'webpack-dev-server' 不是内部或外部命令,也不 是可运行的程序或批处理文件。

    npm init -yes

    {
    "name": "webpack01",
    "scripts": {
      "start": "webpack-dev-server",
      "build": "webpack"
    },
    

    npm run start

    Project is running at http://localhost:8080/

    每次更新后保存会自动编译到浏览器内存 , 而不是磁盘文件,但是页面不会更新

    热更新

    注意路径

    <script type="text/javascript" src="/bundle.min.js" />;
    

    .eslintrc.js 代码质量管理

    npm install eslint eslint-loader -D

    {
      test: /\.js$/,
      exclude: '/node_modules',
      use: {  loader: 'eslint-loader', }
    },
    }
     devtool: 'sourse-map'
    

    单元测试 jest

    jest.io

    npm install jest jest-webpack jest-webpack npm 库里面没有

    const mod = require('../fortest');
    //测试用例名称,函数
    test('fab-7', () => {
      expect(mod.fab(7).toBe(13));
    });
    
    "scripts": {
      "start": "webpack-dev-server",
      "test": "jest-webpack"
    },
    

    npm run test 默认到 tests 目录里面找文件,返回结果

    plugin : 扩展 webpack 功能

    plugin 例子:

    1. postcss.config.js 支持 loader 的使用

    2. 将注入 bundle.js 里面的 css 提取到单独的文件中

      npm install extract-text-webpack-plugin -D

    const ExtractTextPlugin=require('extract-text-webpack-plugin')
    {
      test: /\.css$/,
      // use: ['style-loader', 'css-loader', 'postcss-loader'] //从后往前
      loaders:ExtractTextPlugin.extract({
        use: ['css-loader'] //从后往前
      })
    },
     plugins:[
      new ExtractTextPlugin({
        filename:`[name]_[contenthash:8].css`
      })
    ]
    

    webpack-dev-middleware

    const express = require('express');
    const webpack = require('webpack');
    const webpackMiddleware = require('webpack-dev-middleware');
    const config = require('./webpack.config');
    const app = express();
    const compiler = webpack(config);
    app.use(webpackMiddleware(compiler));
    app.get('/', () => {
      console.log('ds');
    });
    app.listen(9000, '127.0.0.1', function(err) {
      err && console.log(err);
    });
    
    plugins:[
      new HtmlWebpackPlugin({
        filename: 'index.html',
        template: path.resolve(rootPath, 'index.html'),
        chunksSortMode: 'none',
      }),
    ],
    

    删除数组某个元素

    //1splice会改变原来的数组
    const newGoods = prevState.goods;
    newGoods.splice(index, 1);
    return {
      goods: newGoods
    };
    //2 filter,不改变原来数组
    prevState.goods.filter(v => v.id !== good.id); 
    

    数组用 push

    对象用[...state,action.good]

    session

    会话控制,用户信息,购物车商品,用户浏览等都存储在 session 中,保存在服务器端(
    内存、数据库、文件),最优:内存配合 redis,内存性能最好但重启服务器容易丢失数据
    ,redis 备份

    npm install koa-session

    npm install redis

    单元测试

    chai 断言库

    npm install chai

    1. Assert :TDD 风格,类似 nodejs 提供的 Assert 模块
    const { assert } = require('chai');
    const foo = 'bar';
    const beverages = { tea: ['chai', 'matcha', 'oolong'] };
    assert.typeOf(foo, 'number'); //string
    assert.typeOf(foo, 'string', 'foo is string');
    assert.equal(foo, 'bar', 'foo equal "bar"');
    assert.lengthOf(foo, 3, "foo's value has a length of 3");
    assert.lengthOf(beverages.tea, 3, 'beverages has 3 types of tea');
    

    AssertionError: expected 'bar' to be a number

    1. Expect/should: BDD 链式风格 , 接近自然语言
    const { expect } = require('chai');
    const foo = 'bar';
    const beverages = { tea: ['chai', 'matcha', 'oolong'] };
    expect(foo).to.be.a('number');
    expect(foo).to.equal('bar');
    expect(foo).to.have.lengthOf(3);
    expect(beverages)
      .to.have.property('tea')
      .with.lengthOf(3);
    
    const { should } = require('chai').should();
    const foo = 'bar';
    const beverages = { tea: ['chai', 'matcha', 'oolong'] };
    foo.should.be.a('number');
    foo.should.equal('bar');
    foo.should.have.lengthOf(3);
    beverages.should.have.property('tea').with.lengthOf(3);
    

    Mocha 任务运行器

    全局安装均可

    npm install mocha -g

    C:\Users\Administrator\AppData\Roaming\npm\_mocha -> C:\Users\Administrator\AppData\Roaming\npm\node_modules\mocha\bin\_mocha
    C:\Users\Administrator\AppData\Roaming\npm\mocha -> C:\Users\Administrator\AppData\Roaming\npm\node_modules\mocha\bin\mocha
    
    const { should } = require('chai').should();
    const foo = 'bar';
    describe('String', () => {
      it('foo should be a string', () => {
        foo.should.be.a('string');
      });
      it('foo should have lengthOf 3', () => {
        foo.should.have.lengthOf(3);
      });
    });
    describe('equal', () => {
      it('foo should equal bar', () => {
        foo.should.equal('bar');
      });
    });
    

    mocha index.js

    server in http://localhost:8080
     String
        √ foo should be a string
        √ foo should have lengthOf 3
      equal
        √ foo should equal bar
      3 passing (131ms)
    
    describe('asynchronous', () => {
      it('done should be executed after 200ms', done => {
        const fn = () => {
          foo.should.be.a('string');
          done();
        };
        setTimeout(fn, 200);
      });
    });
    
    asynchronous
        √ done should be executed after 200ms (201ms)
    

    删除 done()

     1 failing
      1) asynchronous
           done should be executed after 200ms:
         Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if
    returning a Promise, ensure it resolves. (F:\koa2-tutorial\index.js)
    

    npm install supertest

    koa2

    npm install koa

    ctx:context 上下文

    ctx 参数 说明 备注
    req ctx.req 访问 request 对象 POST
    request koa 对 node 请求的封装,提供很多属性用于开发 HTTP 服务器功能 GET
    res XXX XXX
    response koa 对 node 响应的封装,提供很多属性用于开发 HTTP 服务器功能 XXX
    state 命名空间,用于中间件传递信息和前端视图
    cookies 获取和设置 cookie
    throw 抛出错误,把错误信息返回给用户
    response 属性、方法 说明 备注
    body 返回给用户的响应主体 XX
    status 设置请求状态 200,404,500 等
    type 响应的 Content-Type html;image/png;text/plan
    accepts() 判断期望的响应类型 ctx.resquest.accepts('html')

    ctx.response

    const koa = require('koa');
    const app = new koa();
    app.use(async (ctx, next) => {
      await next();
      ctx.response.type = 'text/html';
      ctx.response.body = '<h1>hello word!!!</h1>';
      console.log('this', this, 'ctx', ctx);
    });
    app.listen(3000, () => {
      console.log('server in http://localhost:3000');
    });
    

    ctx.request 请求

    1. get 请求 --eg. 获取 get 请求中的参数
    app.use(async (ctx, next) => {
      ctx.response.body = {
        url: ctx.request.url,
        query: ctx.request.query,
        querystring: ctx.request.querystring
      };
    });
    

    http://localhost:3000/?search=koa&keywords=context

    {
      "url": "/?search=koa&keywords=context",
      "query": { "search": "koa", "keywords": "context" },
      "querystring": "search=koa&keywords=context"
    }
    
    1. POST 请求 --koa 未封装获取 POST 请求参数的方法
    • 2.1 需解析 context 中原生 Node.js 请求对象 req
    app.use(async (ctx, next) => {
      let postdata = '';
      ctx.req.on('data', data => {
        postdata += data;
      });
      ctx.req.on('end', () => {
        console.log(postdata);
      });
    });
    
    - 2.1.1 启动服务器 node index.js
    - 2.1.2 新命令行窗口 curl 命令模拟 POST 请求
    

    curl -d "param1=value1&param2=value2" http://localhost:3000/

    - 2.1.3 切换回去,看到 log`param1=value1&param2=value2`
    
    • 2.2 koa-bodyparser 中间件 -- 可以把 POST 请求中的参数解析到 ctx.request.body

    npm install koa-bodyparser

    app.use(bodyParser())
    ...
    const bodyParser=require('koa-bodyparser')
    app.use(bodyParser())
    app.use(async (ctx)=>{
        if(ctx.url==='/' && ctx.method==="GET"){
            ctx.type='html';
            let html=`
            <h1>登录</h1>
            <form method="POST" action="/">
            <p>用户名:</p><input name="userName" type="text" />
            <p>密码:</p><input name="password" type="password" />
            <button type="submit">提交</button>
            </form>
            `
            ctx.body=html
        }else if(ctx.url==='/' && ctx.method==='POST'){
            let postData=ctx.request.body
            ctx.body=postData
        }
    })
    //{"userName":"77","password":"777"}解析出一个对象
    

    npm install koa-router

    const bodyParser = require('koa-bodyparser');
    const Router = require('koa-router');
    const router = new Router();
    router.get('/', (ctx, next) => {
      ctx.type = 'html';
      let html = `
        <h1>登录</h1>
        <form method="POST" action="/">
        <p>用户名:</p><input name="userName" type="text" />
        <p>密码:</p><input name="password" type="password" />
        <button type="submit">提交</button>
        </form>
        `;
      ctx.body = html;
    });
    router.post('/', (ctx, next) => {
      let postData = ctx.request.body;
      ctx.body = postData;
      console.log('body', ctx.body);
    });
    app
      .use(bodyParser())
      .use(router.routes())
      .use(router.allowedMethods());
    

    中间件,通过 app.use() 加载,先进后出的堆栈结构,洋葱模型

    app.use(async (ctx,next)=>{
        console.log('1-1')
        await next()
        console.log('1-2')
    })
    app.use(async (ctx, next) => {
      console.log('2-1')
      await next();
      ctx.response.type = 'text/html';
      ctx.response.body = '<h1>hello word!!!</h1>';
      console.log('2-2')
    });
    // 1-1 2-1 2-2 1-2
    
    • 多个中间件组合,使用 koa-compose
    const compose=require('koa-compose')
    async function middlware1(ctx,next) {
        console.log('1-1')
        await next()
        console.log('1-2')
    }
    async function middlware2(ctx,next) {
        console.log('2-1')
        await next();
        ctx.response.type = 'text/html';
        ctx.response.body = '<h1>hello word!!!</h1>';
        console.log('2-2')
    }
    const all=compose([middlware1,middlware2])
    app.use(compose)
    
    常用中间件
    • koa-bodyparser--POST 请求中的参数解析到 ctx.request.body 中,不再用 ctx.req.on
    • koa-router-- 简化路由,不再用 ctx.url 判断路径,ctx.method 判断请求类型
    • npm install koa-static
    • npm install koa-views

    koa-bodyparser

    const koa = require('koa');
    const app = new koa();
    const bodyParser = require('koa-bodyparser');
    const Router = require('koa-router');
    const router = new Router();
    router.get('/user', (ctx, next) => {
      ctx.type = 'html';
      let html = `
        <h1>登录</h1>
        <form method="POST" action="/user/login">
        <p>用户名:</p><input name="userName" type="text" placeholder="aaa" />
        <p>密码:</p><input name="password" type="password" placeholder="111"/>
        <button type="submit">提交</button>
        </form>
        `;
      ctx.response.body = html;
    });
    router.post('/user/login', (ctx, next) => {
      let { userName, password } = ctx.request.body;
      if (userName === 'aaa' && password === '111') {
        ctx.response.body = `hello,${userName}`;
      } else {
        ctx.response.body = '账号输入错误';
      }
      console.log('body', ctx.body);
    });
    app
      .use(bodyParser())
      .use(router.routes())
      .use(router.allowedMethods());
    app.listen(8080, () => {
      console.log('server in http://localhost:8080');
    });
    

    koa-router

    router.get('/home/:id/:name', (ctx, next) => {
      ctx.response.body = '<h1>Hello word!</h1>';
      console.log('params', ctx.params);
    });
    // http://localhost:8080/home/12/aa
    // params {id: "12", name: "aa"}
    

    操作数据库 mysql

    sequelize:ORM 类库,方便操作数据库

    npm install koa koa-bodyparser koa-router koa-cors sequelize mysql2

    // jump-mobile-h5 埋点数据后台测试DEMO
    const koa = require('koa');
    const app = new koa();
    const bodyParser = require('koa-bodyparser');
    const Router = require('koa-router');
    const router = new Router();
    const Sequelize = require('sequelize');//ORM 类库,方便操作数据库
    const cors = require('koa-cors');
    
    // 连接数据库 databaseName,userName,password
    const sequelize = new Sequelize('test', 'root', '111111', {
      host: 'localhost', //数据库服务地址
      dialect: 'mysql' //SQL语言类型
    });
    // 校验数据库连接
    sequelize
      .authenticate()
      .then(() => {
        console.log('connected');
      })
      .catch(err => {
        console.error('connect failed');
      });
    // 定义数据模型
    // 系统数据
    const sysData = sequelize.define('system', {
      uuid: Sequelize.UUID,
      dcEventType: Sequelize.STRING,
      dcPathname: Sequelize.STRING,
      dcCategory: Sequelize.STRING,
      time: Sequelize.STRING
    });
    // 业务数据
    const busData = sequelize.define('buis', {
      comId: Sequelize.STRING,
      dcEventType: Sequelize.STRING,
      dcPathname: Sequelize.STRING,
      dcCategory: Sequelize.STRING,
      time: Sequelize.STRING,
      value: Sequelize.STRING
    });
    // 同步所有模型到数据库
    sequelize
      .sync()
      .then(() => {
        console.log('数据库同步成功')
      })
      .catch(error => {
        console.log(`数据库同步失败:${error}`);
      });
    // 创建数据
    async function createsysData(logData) {
      return sysData.create(logData);
    }
    async function createbusData(logData) {
      return busData.create(logData);
    }
    // 获取POST请求,插入数据
    router.post('/log/jumpDataCollect', async (ctx, next) => {
      let { dcCategory, dcPathname, param } = ctx.request.body;
      let logData = { dcCategory, dcPathname, ...param };
      if (dcCategory === 'system') {
        await createsysData(logData);
      } else if (dcCategory === 'buis') {
        await createbusData(logData);
      } else {
      }
      // 返回
      ctx.type = 'jsonMIME';
      ctx.body = {
        status: 0,
        message: 'success',
        result: logData
      };
    });
    app
      .use(cors()) //解决请求回调跨域
      .use(bodyParser())//POST 请求中的参数解析到 ctx.request.body 中
      .use(router.routes())//路由,结合路径和请求类型
      .use(router.allowedMethods());
    app.listen(8080, () => {
      console.log('server in http://localhost:8080');
    });
    

    相关文章

      网友评论

          本文标题:react知识点

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