zoukankan      html  css  js  c++  java
  • react 基础

    组件状态state 和 props

    • state 和props

    变量是不是能作为state状态

    1.是否能从父组件中获取,如果是它不是一个状态

    2.这个变量是否在组件的整个生命周期中保持不变,如果是它不是一个状态

    3.这个状态是否可以通过其他状态或者属性计算而来,如果是他不是一个状态

    4.这个状态是否在render方法中使用,如果不是,那么他不是一个状态

    不能直接更改state,直接修改state 不会重新触发render,正确的修改方式是setState();

    调用setState 时组件的state并不会立即改变,setStae只是把要修改的状态放入一个队列中,React会优化真正执行的时机,并处于性能原因,可能会将多次setState的状态修改成一次;同理props 也是异步更新的

    所以可以使用 this.setState((preState,props)=>({}));

    State 的更新是一个合并过程,只需要传入发生改变的State,而不是完整组件的state

    state 中包含的所有状态都应该是不可变的对象,当state中的某个状态发生变化时,应该重新创建这个状态对象,而不是直接修改原来的状态对象

    1.状态类型是不可变的类型(数字、字符串、布尔值、null、undefined):这种情况状态是不可变类型,直接赋新值即可

    2.状态类型是数组时:

    this.setState((preState=>({arr:preState.arr.concatt([''])});
    
    this.setSate(preState=>({arr:[...preState.arr,'new props']}));

    当从数组中截取部分元素可以用slice 方法

    不要用push/pop shift/unshift splice 等方法,修改数组类型的状态,因为这些方法都是在原有数组的基础上修改的,而concae slice filter 会返回新数组

    3.状态类型是普通对象(不包含字符串数组)

    //使用Object assign 语法
    this
    .setSate(preState=>({obj:Object.assign({},preState.obj,{newprops:'value'}}));
    //使用对象扩展语法

    this.setSate(preState=>({obj:{...preState,newProps:'value'}));

    组件之间通信

    父子组件通信:父组件向子组件传递props 数据

    子组件向父组件通信时:父组件可以通子组件的props 传递给子组件一个回调函数,子组件在需要改变父组件数据时调用这个回调函数即可

    兄弟组件通信:(具有相同父组件的但不是父子关系的组件成为兄弟组件,兄弟组件并不一定处于同一层级)兄弟组件不能直接相互传递数据,需要通过状态提升的方式实现兄弟组件的通信,即把组件之间需要共享的状态保存到距离他们最近的共同父组件内

     context

    context 上下文,让任意层的子组件都可以获取父组件中的状态和方法

    父组件

    getChildContext(){}// 返回共享数据

    fatherClass.childContextTypes={ props:ProoTyoes.func} //声明属性类型信息

    子组件

    childClass.childContextTypes={ props:ProoTyoes.func} //声明属性类型信息

    this.context.props; // 通过this.context 获取

    注意:context 可能致使应用数据变得换换,在未来的react 版本中可能被修改或者废弃

     ref

    ref可以获取任意DOM元素,可以控制元素的焦点、文本的选择、或者第三方操作DOM的库集成,但是它破坏了React中以props 为数据传递介质的典型数据流应避免过度使用

    注意只能为类组件定义ref 属性,而不能为函数组件定义ref 属性(不起作用),ref 能获取到子组件的实例对象,而不能获取到某个DOM 元素

    高阶组件

    •  概念

    高阶组件是React 中一个很重要且复杂的概念,主要用来实现逻辑的抽象和复用。高阶组件简称HOC,接收react组件作为参数,并返回一个新的React 组件,高阶组件本质上也是一个函数,不是是组件

    形式=》 const EnhancedComponent higherOrderComponent(WrappedComponent)

    • 使用场景:

    1.操作props

    在被包装组件接收props 前,高阶组件可以先拦截到props对props 执行增加、删除、修改的操作,然后在将处理后的props 传递给被包装组件

    2.通过ref访问组件实例 

    高洁组件通过ref 获取被包装组件的实力引用,然后高阶组件就具备了直接造作被包装组件的属性和方法

    3. 组件状态提升

    高阶组件可以通过包装组件的状态,及相应状态的处理方法提升到高洁组件自身内部实现,被包装的组件无状态变化

    4.用其他元素组件包装

    在高阶组件渲被包装元素时添加额外元素,这种情况通常用于为被包装元素增加布局或修改样式

    • 参数传递

    function higherOrderComponent (WrappedComponent,key)

                         =>

    function higherOrderComponent  = (key)=>(WrappedComponent)=>{

    ...

    }

    • 继承方式实现高阶组件
    function  withAuth(wrapperdComponent){
       return class extends wrapperedComponent{
           render(){
                 if(this.props.login) {return super.render}
                 else{ return null;}
                  
            }
        
        }
    
    
    }        

    继承方式实现的高阶组件对包装组件具有侵入性,当组合多个高阶组件使用是很容易因为子组件忘记通过super 调用父组件方法导致逻辑对视,因此在使用高级组件时,应尽量使用代理方式实现高阶组价

    注意事项

    1.在开发测试阶段为了区分不同的高阶组件,需要对高阶组件的显示名称做自定义处理

    static dispalyName ='HOC(${getDispalyName(wrappedcomponent)})';
    
    function getDispalyName(wrappedcomponent){ return wrappedcomponent.displayName||wrappedcomponent.name||'Component';}

    2.不要在组件的render 方法中使用高阶组件,尽量不要在组件的其他生命周期中使用,因为每次调用高阶组件都会返回一个新的组件,每一次render,前一次的高阶组件回呗卸载然后重新挂载,及影响效率又丢失了组件及其子组件的状态

    3.高阶组件返回的新组建不包含被包装组件的静态方法

    4.ref 不会床底给被包装组件

    5.高阶组件与父组件很相似,高阶组件强调的是逻辑的抽象

    React Router

    多页面应用 ,页面路由的控制由服务端控制,这种路由方式成宿后端路由

    单页面应用url 发生变化并不会向服务器发送新的请求,所以逻辑页面的路由只能由前端负责,这种路由方式成为前端路由

    BrowserRouter 使用HTML5 的history API实现UI和 URL 的同步

    HashRouter 使用URI 的hash 实现UI和 URL 的同步

    Router 会创建一个history 对象,history 用来跟踪URL,当url发生变化时Router de 后代组件会重新弄渲染,其他组件可以通过context 来获取history 对象,React Router 中的其他子组件鼻祖作为Router 的后代组件使用,且React Router 只能有唯一的一个子元素

    • 路由配置

    1.path: 每个路由都需要定义一个path,当使用BrowseRouter 时,path 用来描述这个route 匹配的url 的pathName;当使用hash Router 是,path用来描述这个route 匹配url 的hash

    2.match

      url 和route 匹配时,Route 会创建一个match 对象最为props 传递给子对象,其中match 包含

      1.params:'' 从path 中解析的参数

      2.isExact:布尔值当URL 完全匹配时值为true

      3:path route 的path

      4.url: url的匹配部分

    3.Route 如何渲染组件方式

    Component:

    <Route path="/foo" component={Foo}></Route>

    render: render 的值是一个函数,这个函数返回一个React元素,这种房还是可以方便的为待渲染组件传递额外属性

    <Route path="/foo"  render={(props)=>()}></Route>

    children: children 的值也是一个函数,函数返回要渲染的React 元素,无论是否匹配成功,children 返回的组件都被渲染,但是当匹配不成功嗯嗯斥候match 的属性为空

    <Route path="/foo" children={(props)=>()}></Route>

     4.swith 和 exact

    Swith: 只匹配第一个Route 进行渲染

    exact: url 和route 完全匹配

    5.嵌套路由

    在Route 渲染的组件内部定义新的Route

    6.链接

     Link 是React Route 提供的链接组件,一个Link 组件定义了当点击该Link时,页面应该如何路由

    <Link to{{
      pathname:'',
      search:"?'',
      hash:'',
      state:{}
    }}
    >
    </Link>

     除了使用Link 外我们可以使用history 对象手动实现导航

    history.push(path,[state]);

    history.repalace(path,[state]);

    • Redux

    三大原则:

    1、唯一数据源:Redux 应用只维护一个全局的状态对象,存储在Redux 的store 中

    2、保持应用状态只读: 在任何情况下都不能直接修改应用状态,当需要修改应用状态时,必须发送一个action,由这个action 描述如何修改应用状态

    3、应用状态的改变通过存函数完成: reducer 必须是存函数,当reducer 接收action 时,不能直接修改原来的状态U帝乡,而是创建一个新的状态返回

    纯函数:1.对于同样的参数值,函数的返回结果相同,即函数的结果不依赖任何在程序执行过程中可能改变的变量

                   2.函数的执行不会产生副作用,例如修改外部对象或输出到I/O 设备

    主要组成:

    action: 是Redux 消息载体,是store唯一的信息来源,把action 发送给store 必须通过store 的dispath 方法,action是普通的javaScript 对象,每一个action 必须有一个type 属性描述action,的类型,type一般被定义为字符串常量,除了type 外action 的结构由自己决定

                一般action 通过action Creator 来创建,action creator 是返回action的函数

    reducer: reducer 根据action 做出响应,决定如何修改应用的状态state,所以在编写reducer 前设计好state,state 既可以包含从服务器获取的数据,也可以包含UI 状态

    store 是Redux 中的一个队形,是action和reducer 之间的桥梁   

              state主要负责:保存应用状态,通过getState() 方法访问应用状态,通过dispath更新应用状态、通过subscribe(listener) 监听应用状态

    一个Redux 应用只有一个store.store 保存了唯一的数据源,store 通过createStore() 函数创建、创建需要reducer 作为参数

    //导入
    import {createStore} from 'redux'//创建
    let store =crreateStore(reducer,initState}
    
    //获取
    const state =store.getState()
    
    //修改 修改完成后可通过store.getState获取新状态
    store.dispath(actionCreator());
    
    //为了能准确获取到应用状态的更新时间,需要向store注册一个监听函数
    let unsubscribe =store.subscribe(()=>{});
    • 在React 使用Redux
     //安装redux  
    
    npm install react-redux
    
    //导入
    
    import {connect } from 'react-redux';
    
    //使用
    
    connect( mapStateToProps,mapDispathToProps);

    组织项目结构

    1. 按照文件类型
    2. 按照页面功能
    3. Ducks

    合理设计state(按照数据库设计state,把state 看做是一个数据库,state 中的每一部分状态看做是数据库中的一张表,状态中的每一个字段对应表的一个字段)

    1. 数据按照领域分类存储到不同的表中,不同的表中存储的列数据不能重复
    2. 每一列的数据都依赖主键
    3. 表中除了主键以外,其他列互相不能有直接的依赖关系

    state 设计原则

    1. 把整个应用的状态按照领域分成若干个子状态,子状态之间不能保存重复的数据
    2. state 以键值对的结构存储数据,以记录的key 或者id 作为记录的索引,记录中的其他字段都依赖与索引
    3. state 中不能保存可以通过state 中的已有字段计算而来的数据
    APP:{
        requestQuantity:0,
        error:null,
        ui:{
             addDialogOpen:false,
             editDialogOpen:false
        }
    },
    auth:{
        userid:null,
        userName
    }
  • 相关阅读:
    搭建SpringCloud之注册中心Eureka
    学习角色管理模块错误总结---基于SpringMVC框架
    【转】Eclipse 单步调试
    [转]MyBatis的foreach语句详解
    解决pom.xml文件 ---- web.xml is missing and <failOnMissingWebXml> is set to true
    解决Dynamic Web Module 3.0 Requires Java 1.6 or newer
    用maven在eclipse用spring建javaweb工程(一)
    【转载】Eclipse 断点调试
    学习大神笔记之“MyBatis学习总结(三)”
    学习大神笔记之“MyBatis学习总结(二)”
  • 原文地址:https://www.cnblogs.com/canghaiyimeng/p/9667580.html
Copyright © 2011-2022 走看看