zoukankan      html  css  js  c++  java
  • vue react angular

    angular 代码比较难懂,性能也比较差

    vue----双向数据流  双向数据流,就是内存的改变影响页面的改变,页面的改变影响内存的改变;

    import 和require区别

    import es6的语法,属于加载前置的机制,因此将其全放在代码顶部,代码解析逐个import获取一个引入的列表,先引入依赖,再向下

    执行代码,加载前置

    require 是node的语法,require懒加载,加载滞后,带啊吗执行到哪里才进行加载

    导入文件

    默认导入   import xxx from './xxx.js'   导出: export default 数据

    按需导入  import {} from './aaa.js'    先定义再导出    导出:export const aa=2; 或者 let aa=2; export {aa}

    全体导入 import * as obj from './bbb.js'

    需要把import放在最上方,否则会报错

    react

    react-单向数据流

    单向数据流,只处理内存的改变,需要自己处理页面的改变来影响内存(通过事件),调用函数

    react没有指令

    脚手架,create-react-app

    内部如果以来yarn npm i -g yarn   yarn与npm类似的一个包管理工具

    function obj1(){} let o=new obj();
    
    obj1.prototype.age=1;
    
    //等同
    
    class obj1{
    
    //静态属性
    
    static staticAge=99;
    
    //静态函数
    
    static staticFun=function(){console.log('静态函数');console.log(this);//构造函数对象}
    
    age=1;
    
    //箭头函数才向上用别人的this
    
    myFun(){console.log('实例的函数',this.age)}//上下文 this与function是一致的,用的就是自己的
    
    }

    类class

    类相当于实例的原型,所有在类中定义的方法,都会被实例继承,如果在一个方法或者属性前面加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用的,这就称为‘静态方法’‘静态属性’,所以静态方法不能访问实例

    通知视图更新

    this.setState({num:1});

    react中有变化的属性

    在react中class的类的关键字,所以样式就不能使用class,需要改成className

    class:className

    可以写js,for是js中的关键字,需要改成htmlFor

    for:htmlFor

    推荐的工具链

    • React创建一个单页应用 使用create-react-app
    • 用node构建服务器端渲染的网站使用Next.js
    • 构建面向内容的静态网站,Gatsby

    Create React App

    是一个用React创建新的单页应用的最佳方式,需要node>=8.10和npm>=5.6

    创建项目

    npx create-react-app my-app

    cd my-app

    npm start

    npx是npm5.2+附带的package运行工具

    Create React App不会处理后台逻辑或者操作数据库,它只是创建一个前端构建流水线。

    jsx语法

    js+xml

    jsx中插入js代码,js代码需要加{}

    在jsx语法中,你可以在大括号中放置任何有效的js表达式

    jsx也是一个表达式

    在编译之后,jsx表达式会被转为普通js函数调用,并且对其取值后得到js对象。也就是说,你可以在if语句

    和for循环的代码块中使用jsx,将jsx复制给变量,当做参数传入,以及从函数中返回JSX

    JSX 特定属性

    你可以通过使用引号,来将属性值指定为字符串字面量:

    const element = <div tabIndex="0"></div>;

    也可以使用大括号,来在属性值中插入一个 JavaScript 表达式:

    const element = <img src={user.avatarUrl}></img>;

    在属性中嵌入 JavaScript 表达式时,不要在大括号外面加上引号。你应该仅使用引号(对于字符串值)或大括号(对于表达式)中的一个,对于同一属性不能同时使用这两种符号。

    JSX 防止注入攻击

    React DOM 在渲染所有输入内容之前,默认会进行转义。它可以确保在你的应用中,永远不会注入那些并非自己明确编写的内容。所有的内容在渲染之前都被转换成了字符串。这样可以有效地防止 XSS(cross-site-scripting, 跨站脚本)攻击。

    JSX 表示对象

    Babel 会把 JSX 转译成一个名为 React.createElement() 函数调用。

    元素是构成 React 应用的最小砖块。

    组件是由元素构成的。

    注释需要写在花括号中,实例如下{/*注释...*/}

    JSX 允许在模板中插入数组,数组会自动展开所有成员

    更新已渲染的元素

    React 元素是不可变对象。一旦被创建,你就无法更改它的子元素或者属性。

    根据我们已有的知识,更新 UI 唯一的方式是创建一个全新的元素,并将其传入 ReactDOM.render()

    考虑一个计时器的例子:

    function tick() {
      const element = (
        <div>
          <h1>Hello, world!</h1>
          <h2>It is {new Date().toLocaleTimeString()}.</h2>
        </div>
      );
      ReactDOM.render(element, document.getElementById('root'));}
    
    setInterval(tick, 1000);

    在实践中,大多数 React 应用只会调用一次 ReactDOM.render()

    组件 & Props

    函数组件与class组件

    最简单的方式就是编写js函数:

    function Welcome(){

    return <h1>hello world</h1>

    }

    注意: 组件名称必须以大写字母开头。

    React 会将以小写字母开头的组件视为原生 DOM 标签。

    Props 的只读性

    组件无论是使用函数声明还是通过 class 声明,都决不能修改自身的 props。

    所有 React 组件都必须像纯函数一样保护它们的 props 不被更改。

    State & 生命周期

    State 与 props 类似,但是 state 是私有的,并且完全受控于当前组件。

    Class 组件应该始终使用 props 参数来调用父类的构造函数。

    react生命周期:

    componentWillMount//不推荐在此处发送请求,原因:可能会造成渲染的阻塞

    componentDidMount   //挂载,数据已经装载,组件已经被渲染到DOM中后运行,会引起二次render,在这里发网络请求

    componentWillUnMount //卸载

    componentWillUpdate

    componentDidUpdate

    正确地使用 State

    不要直接修改 State,而是应该使用 setState():

    State 的更新可能是异步的

    因为 this.props 和 this.state 可能会异步更新,所以你不要依赖他们的值来更新下一个状态。

    例如,此代码可能会无法更新计数器:

    // Wrong
    this.setState({
      counter: this.state.counter + this.props.increment,
    });

    要解决这个问题,可以让 setState() 接收一个函数而不是一个对象。这个函数用上一个 state 作为第一个参数,将此次更新被应用时的 props 做为第二个参数:

    // Correct
    this.setState((state, props) => ({
      counter: state.counter + props.increment
    }));

    数据是向下流动的

    这通常会被叫做“自上而下”或是“单向”的数据流。任何的 state 总是所属于特定的组件,而且从该 state 派生的任何数据或 UI 只能影响树中“低于”它们的组件。

    事件处理

    • React 事件的命名采用小驼峰式(camelCase),而不是纯小写。
    • 使用 JSX 语法时你需要传入一个函数作为事件处理函数,而不是一个字符串。

    向事件处理程序传递参数

    在循环中,通常我们会为事件处理函数传递额外的参数。例如,若 id 是你要删除那一行的 ID,以下两种方式都可以向事件处理函数传递参数:

    <button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
    <button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>

    上述两种方式是等价的,分别通过箭头函数和 Function.prototype.bind 来实现。

    在这两种情况下,React 的事件对象 e 会被作为第二个参数传递。如果通过箭头函数的方式,事件对象必须显式的进行传递,而通过 bind 的方式,事件对象以及更多的参数将会被隐式的进行传递。

    key

    key 帮助 React 识别哪些元素改变了,比如被添加或删除。因此你应当给数组中的每一个元素赋予一个确定的标识

    用 key 提取组件

    元素的 key 只有放在就近的数组上下文中才有意义。

    一个好的经验法则是:在 map() 方法中的元素需要设置 key 属性。

    key 只是在兄弟节点之间必须唯一

    key 会传递信息给 React ,但不会传递给你的组件。如果你的组件中需要使用 key 属性的值,请用其他属性名显式传递这个值

    JSX 允许在大括号中嵌入任何表达式

     props默认值和类型定义(属性的约定和默认值)

    需要引入"prop-types"

    import PropTypes from 'prop-types'

    static propTypes={//定义props数据类型

    text:PropsTypes.string//number(数字类型) .isRequired(必须)

    }

    static defaultProps={//定义props默认值

    text:'abc'

    }

    这样在子组件中就可以直接使用this.props.text,如果父组件传值,就用父组件的值,否则使用默认值

    内置便捷函数

    React.Children.map 返回一个数组

    React.Children.forEach 遍历数组

    this.props.children有可能有三种数据结构   对象/数组/undefined

    let children =this.props.children;

    React.Children.map(children,()=>{})//返回数组可以过滤null/undefined,避免传递参数中出现null undefined

    template

    render函数中返回的html,只能有一个根节点,会衍生处很多多余的div,

    可以使用<React.Fragment></React.Fragment>不会生成多余的dom元素;

    demo:

    render() {
            var style = { display: 'none' };
            return (<div>
                <form className="App" onSubmit={this.submitForm} target='id_iframe'>
                    <h1>this is my first react app2</h1>
                    <p>姓名:{this.state.name}</p>
                    姓名:<input type='text' name='name' value={this.state.name} onChange={this.clickHandler} />
                    <p>年龄:{this.state.age}</p>
                    年龄:<input type='text' name='age' value={this.state.age} onChange={this.clickHandler} />
                    <input type='submit' value='提交' />
                </form>,
                <iframe id="id_iframe" name="id_iframe" style={style} ></iframe>
            </div>);
        }

    可以改为:

    render() {
            var style = { display: 'none' };
            return (<React.Fragment>
                <form className="App" onSubmit={this.submitForm} target='id_iframe'>
                    <h1>this is my first react app2</h1>
                    <p>姓名:{this.state.name}</p>
                    姓名:<input type='text' name='name' value={this.state.name} onChange={this.clickHandler} />
                    <p>年龄:{this.state.age}</p>
                    年龄:<input type='text' name='age' value={this.state.age} onChange={this.clickHandler} />
                    <input type='submit' value='提交' />
                </form>,
                <iframe id="id_iframe" name="id_iframe" style={style} ></iframe>
            </React.Fragment>);
        }

    在react16+可以使用数组:

    render() {
            var style = { display: 'none' };
            return[
                <form className="App" onSubmit={this.submitForm} target='id_iframe'>
                    <h1>this is my first react app2</h1>
                    <p>姓名:{this.state.name}</p>
                    姓名:<input type='text' name='name' value={this.state.name} onChange={this.clickHandler} />
                    <p>年龄:{this.state.age}</p>
                    年龄:<input type='text' name='age' value={this.state.age} onChange={this.clickHandler} />
                    <input type='submit' value='提交' />
                </form>,
                <iframe id="id_iframe" name="id_iframe" style={style} ></iframe>
            ];
        }

    推荐使用<React.Fragment>比较灵活,如果不需要在fragment中添加任何prop且你的工具支持的时候,你可以使用短语法<></>(key 是唯一可以传递给 Fragment 的属性)

    react15与16的区别

    主要在于:

    1 语法区别

    2 propType和getDefaultProps

    import React, { Component } from 'react'
    import PropTypes from 'prop-types'
    class demo extends Component {
    static propTypes={//定义props数据类型
    text:PropsTypes.string//number(数字类型) .isRequired(必须)
    
    }
    static defaultProps={//定义props默认值
    text:'abc'
    }
    constructor(props){
    this.setState({
    text:props.text
    });
    }
    render(){
    return <div>this.state.text</div>
    }
    
    }

    3 状态的区别

     

    4 this的指向

     

    5 Mixins

     

     高阶组件 

    接受一个组件,render一个组件,从而添加一些功能,高阶组件是参数为组件,返回值为新组件的函数

    Mixins: 作为函数接受一个组件,render那个组件,在js部分先执行,拿到组件对象<组件/>使用

    获取dom元素

    在元素上使用ref='xxx'

    在组件中使用this.refs.xxx

    请求

    axios

    路由

    react-router-dom(在浏览器使用)

    react-router-naticve(开发手机原生应用使用的),推荐使用react-navigation

    使用

    npm i react-router-dom -S

    引入对象

    按需引入:HashRouter BrowserRouter,

    • Route  一条路由记录
    • HashRouter 代表路由框架的坑
    • BrowserRouter    最终没有#的方式,原理基于clcik+history.pushState
    • Route代表锚点以及组件和填入的位置
    • Switch 选择一个(横向选择一个,被其包裹的Route从上到下,指挥匹配一个(选其一))
    • exact 精确匹配(纵向匹配一个)

    exact  精确匹配锚点;应用场景:首页"/"需要使用,因为范围太大,会匹配很多东西(其他路由不适用,为了能使用嵌套路由)

    默认重定向(相当于404)

    放在路由最后一位,用来处理页面找不到,配合Switch

    NavLink/Link类似router-link

    NavLink按需引入 import {NavLink} from ‘react-router-dom’

    当作组件来使用,其中属性to(路径,与Route中的Path匹配)

    动态路由:

    <Route path='/user/:id' component={UserInfo} />
    <Link to='/user/11'>userInfo</Link>
    参数获取params:
     componentDidMount() {
            console.log(this.props.match.params);
        }

    js 方法:this.props.history.push('/user/11');

    路由参数:

    <Link to={{ pathname: '/demo', query: { id: 10 } }} >demo</Link>

    参数获取query:

     componentWillReceiveProps(nextProps) {
            console.log(this.props.location.query && this.props.location.query.id == nextProps.location.query.id);
            if (this.props.location.query && this.props.location.query.id == nextProps.location.query.id)
                return false;//如果参数没有改变,没有操作
            console.log(nextProps.location.query.id);
    
        }

     js 方法:this.props.history.push({ pathname: '/demo', query: { id: 10 } });

     嵌套路由中出现的问题:

    在子路由中也使用BrowserRouter,会导致link跳转不起作用,需要删除子组件中BrowserRouter,只在App.js中

    有BrowserRouter

    this.setState({},()=>{

    //在react异步渲染之后的行为,类似vue中的this.$nextTick函数

    //your code

    });

    react中css中局部作用域

    react与vue不同,vue可以通过在script中设置scoped来限制样式的生效范围,不至于样式污染。

    css modules是从工具层面给出的一套生成局部css的规范,本质还是生成全局位置的css定义,webpack实现了这套规范。

    css modules是默认开启的,所以我们只需要将原来的.less 或.css文件改为.module.less .module.css

    例如:App.module.css

    .app{background-color:red}

    z在react的js文件引入:

    import App from './index.module.css'

    使用

    <div classsName={App,.app}></div>

    渲染结果

    可以看到class是一堆啥玩意的名字,实际上它 是 App--<hash数值>,这个 hash 值是全局唯一的,比如通过文件路径来获得,这样 class 名称就做到了全局唯一。通过全局唯一的 CSS 命名,我们变相地获得了局部作用域的 CSS(scoped CSS)。如果一个 CSS 文件仅仅是作用在某个局部的话,我们称这样一个 CSS 文件为 CSS module

    状态提升

    通常,多个组件需要反映相同的变化数据,这时我们建议将共享状态提升到最近的共同父组件中去。让我们看看它是如何运作的;

    多个组件公用一个属性,就可以把这个属性提升到父组件中。通过props传递给子组件,同时传入修改属性所用的方法,子组件中修改数值时直接调用props中父组件传入的方法,可以实现数据多个组件共享,同时props中传入的数据在子组件中是不能修改的,所以需要传入父组件定义的修改属性的方法,在父组件中实现数据的变更

    组合 vs 继承

    React 有十分强大的组合模式。我们推荐使用组合而非继承来实现组件间的代码重用。

    相当于vue中组件的slot props.children React.Children

    组件可以接受任意 props,包括基本数据类型,React 元素以及函数。

    如果你想要在组件间复用非 UI 的功能,我们建议将其提取为一个单独的 JavaScript 模块,如函数、对象或者类。组件可以直接引入(import)而无需通过 extend 继承它们。

    根据单一功能原则来判定组件的范围

    代码分割

    import()

    在你的应用中引入代码分割的最佳方式是通过动态 import() 语法。

    使用之前:

    import { add } from './math';
    
    console.log(add(16, 26));

    使用之后:

    import("./math").then(math => {
      console.log(math.add(16, 26));
    });

    React.lazy

    不支持服务端渲染

    React.lazy 函数能让你像渲染常规组件一样处理动态引入(的组件)。

    使用之前:

    import OtherComponent from './OtherComponent';

    使用之后:

    const OtherComponent = React.lazy(() => import('./OtherComponent'));

    React.lazy 接受一个函数,这个函数需要动态调用 import()。它必须返回一个 Promise,该 Promise 需要 resolve 一个 defalut export 的 React 组件

    然后应在 Suspense 组件中渲染 lazy 组件,如此使得我们可以使用在等待加载 lazy 组件时做优雅降级(如 loading 指示器等)。

    import React, { Suspense } from 'react';
    
    const OtherComponent = React.lazy(() => import('./OtherComponent'));
    
    function MyComponent() {
      return (
        <div>
          <Suspense fallback={<div>Loading...</div>}>
            <OtherComponent />
          </Suspense>
        </div>
      );
    }

    fallback 属性接受任何在组件加载过程中你想展示的 React 元素。你可以将 Suspense 组件置于懒加载组件之上的任何位置。你甚至可以用一个 Suspense 组件包裹多个懒加载组件。

    异常捕获边界

    如果模块加载失败(如网络问题),它会触发一个错误。你可以通过异常捕获边界(Error boundaries)技术来处理这些情况,以显示良好的用户体验并管理恢复事宜。

    import React, { Suspense } from 'react';
    import MyErrorBoundary from './MyErrorBoundary';
    
    const OtherComponent = React.lazy(() => import('./OtherComponent'));
    const AnotherComponent = React.lazy(() => import('./AnotherComponent'));
    
    const MyComponent = () => (
      <div>
        <MyErrorBoundary>
          <Suspense fallback={<div>Loading...</div>}>
            <section>
              <OtherComponent />
              <AnotherComponent />
            </section>
          </Suspense>
        </MyErrorBoundary>
      </div>
    );

    React.lazy 目前只支持默认导出(default exports)

    Context

    Context 设计目的是为了共享那些对于一个组件树而言是“全局”的数据,例如当前认证的用户、主题或首选语言。

    React.createContext

    创建一个 Context 对象。当 React 渲染一个订阅了这个 Context 对象的组件,这个组件会从组件树中离自身最近的那个匹配的 Provider 中读取到当前的 context 值。

    Context 主要应用场景在于很多不同层级的组件需要访问同样一些的数据。请谨慎使用,因为这会使得组件的复用性变差。

    如果你只是想避免层层传递一些属性,组件组合(component composition)有时候是一个比 context 更好的解决方案

    React 组件 API

    设置状态 setState

    替换状态 replaceState

    设置属性 setProps

    替换属性 replaceProps

    强制更新 forceUpdate

    获取dom节点 findDomNode

    判断组件挂在状态 isMounted

    设置状态:setState

    setState(object nextState[, function callback])

    参数说明

    • nextState,将要设置的新状态,该状态会和当前的state合并
    • callback,可选参数,回调函数。该函数会在setState设置成功,且组件重新渲染后调用。

    替换状态:replaceState

    replaceState()方法与setState()类似,但是方法只会保留nextState中状态,原state不在nextState中的状态都会被删除。

    设置属性:setProps

    setProps(object nextProps[, function callback])
    • nextProps,将要设置的新属性,该状态会和当前的props合并
    • callback,可选参数,回调函数。该函数会在setProps设置成功,且组件重新渲染后调用。

    设置组件属性,并重新渲染组件。

    props相当于组件的数据流,它总是会从父组件向下传递至所有的子组件中。当和一个外部的JavaScript应用集成时,我们可能会需要向组件传递数据或通知React.render()组件需要重新渲染,可以使用setProps()

    更新组件,我可以在节点上再次调用React.render(),也可以通过setProps()方法改变组件属性,触发组件重新渲染。

    替换属性:replaceProps

    replaceProps()方法与setProps类似,但它会删除原有 props。

    强制更新:forceUpdate

    forceUpdate([function callback])

    forceUpdate()方法会使组件调用自身的render()方法重新渲染组件,组件的子组件也会调用自己的render()。但是,组件重新渲染时,依然会读取this.props和this.state,如果状态没有改变,那么React只会更新DOM。

    forceUpdate()方法适用于this.props和this.state之外的组件重绘(如:修改了this.state后),通过该方法通知React需要调用render()

    一般来说,应该尽量避免使用forceUpdate(),而仅从this.props和this.state中读取状态并由React触发render()调用。

    获取DOM节点:findDOMNode

    DOMElement findDOMNode()
    • 返回值:DOM元素DOMElement
    • 如果组件已经挂载到DOM中,该方法返回对应的本地浏览器 DOM 元素。当render返回null 或 false时,this.findDOMNode()也会返回null。从DOM 中读取值的时候,该方法很有用,如:获取表单字段的值和做一些 DOM 操作。
  • 相关阅读:
    js的BOM对象完全解析
    转:JavaScript中的this陷阱的最全收集
    转载:冷门js技巧
    MVVM的架构设计与团队协作 with StoryBoard
    ReactiveCocoa & FRP & MVVM
    ReactiveCocoa的冷信号与热信号 探讨
    Git本地项目上传 & SourceTree & GitHub 简单使用
    Monad / Functor / Applicative 浅析
    map & flatMap 浅析
    Swift -> Let & Var 背后编程模式 探讨
  • 原文地址:https://www.cnblogs.com/xiaofenguo/p/13210851.html
Copyright © 2011-2022 走看看