• react


    前言:首先掌握 构造函数,原型,原型对象,class类,class类的继承的概念

    一,概念

    1. react 如何实现组件化

      react中有组件化的概念,但是,并不像是vue这样的组件模板文件,react中,一切都是以js来表现的 es6和es7

    2. react 核心概念
    1. 虚拟dom:用js对象的形式,来模拟页面上的嵌套关系

    2. diff算法:对比dom和虚拟dom

      (1)tree diff:dom树节点对比

      (2)component diff: 在 tree diff的基础上, 组件级别的对比

      (3)element diff:组件对比的同时,元素级别的对比

      层层递进的关系

    3.webpack

      因为webpack是基于node构建的

      和export defult 不同,这里是node里面的语法,common.js语法

    module.exports = {}
    4.node 和 chrome的关系

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

    5.本地编译和打包编译

    本地编译代码时, npm run dev 时,在内存中创建了文件,实质找不到文件,项目中右键检查源代码时,srcipt标签引入的是 src="app.js",并且app.js文件里并没有被压缩,假设本地运行的端口是8080,那么在localhost:8080/app.js下会看到你在内存中编译的js代码

    但是生产环境引入了多个压缩的js文件

    6.react脚手架

        查看脚手架版本 create-react-app --version

    1. 创建项目 npm init react-app my-app 或者 create-react-app myapp

    2. 解决找不到命令报错:https://blog.csdn.net/weixin_36775115/article/details/103599176

     二,基础

    1. react创建dom元素

      react创建虚拟dom并渲染到页面,我们实际开发过程中用jsx语法写,其实也是利用了babel将jsx语法转成了这种形式,让浏览器解析

     1 // 1. 创建dom元素 createElement(
     2 // 参数1:创建的元素的类型,字符串,表示元素的名称
     3 // 参数2: 是一个对象或是null,表示dom元素的属性,
     4 // 参数3,子节点(包括其他虚拟dom,获取  文本子节点)
     5 // 参数n: 其他子节点
     6 // )
     7 // const myh2 = React.createElement('h2', null, '这是创建的子节点');
     8 
     9 //当设置属性class类名时,应写成className
    10 const myh2 = React.createElement('h2', { className: 'myh2', title: 'this is dom'}, '这是创建的子节点');
    11 const mydiv = React.createElement('div', null, '给h1外面套一层div', myh2)     // 给h2外面套一层div
    12 //ReactDOM.render() 将虚拟dom渲染到页面
    13 // 1. 要渲染的虚拟dom元素
    14 // 2. 指定的容器
    15 ReactDOM.render(mydiv, document.getElementById('app'))

    2. jsx语法        https://reactjs.bootcss.com/docs/introducing-jsx.html

    在js中混合写入html语法,叫做jsx,符合xml规范的js,jsx语法的本质在运行的时候被babel转换成 React.createElement()的形式

    和Vue的插值表达式一样,循环的时候也要加key,由于虚拟dom的原因,防止dom元素被复用 

    创建元素时单行可以不用加(),多行必须要加()

    1 let name = '小明'
    2 let a = 10
    3 let boo = true
    4 let title = 'myh1'
    5 const h1 = <h1>这里是h1</h1>
    6 const myh1 = <div class={title}>{a + 2} {name} {boo ? '' : ''} {h1}</div>
    7 
    8 ReactDOM.render(myh1, document.getElementById("app"))

    jsx语法里写注释  /* */形式

     1 {/* {a + 2} {name} {boo ? '真' : '假'} {h1} */} 

    jsx语法中给元素添加类名,使用className代替

    引入图片,变量的形式或者使用node中的require

    1 <img src={imageurl} alt="" />
    2 <img style={{height: '100px'}} src={require('../assets/image/2.jpg')} alt=""/>

    3. react 创建组件

    组件名称必须以大写字母开头

    React 会将以小写字母开头的组件视为原生 DOM 标签。例如,<div /> 代表 HTML 的 div 标签,而 <Welcome /> 则代表一个组件,并且需在作用域内使用 Welcome

      3.1 第一种,构造函数创建组件,必须有return,否则报错,和vue一样,必须要有一个根元素,构造函数名即为组件名

        如果不想让共同的根元素显示出来使用:fragment标签 或者是 <></> 空标签

    1 function Hello() {
    2   return <div>这里是组件</div>
    3 }
    4 
    5 ReactDOM.render(<div>
    6   我要创建组件
    7   <Hello></Hello>
    8 </div>,
    9   document.getElementById("app"))

    react工具

    https://github.com/facebook/react-devtools

    https://github.com/facebook/react

      react组件传值(props)

    不管是vue,还是react,组件中props接受的参数永远都是只读的,react中props就是所谓的组件接受的参数,只要外界传值,那就直接使用props就行了,不管是函数是组件还是class类组件

     1 //定义子组件
     2 function Hello(props) {
     3   // console.log(props)    //形参接受外界传过来的参数,和vue一样,props接受的参数是只读的,不可修改
     4   let { userinfo, user } = props
     5   return <div>这里是组件 {userinfo.name}</div>
     6 }
     7 
     8 const userobj = {
     9   name: 'shun',
    10   age: 18
    11 }
    12 const userarr = [{ id: 0, gril: 'ppp' }, { id: 1, gril: 'uuu' }]
    13 
    14 ReactDOM.render(<div>
    15   我要创建组件
    16   {/* 传递参数 */}
    17   <Hello userinfo={userobj} user={userarr}></Hello>   
    18 </div>,
    19   document.getElementById("app"))

    自组件给父组件传值 (和vue一样,需要事件)

      子组件:通过 this.props.自定义的事件名(传递的参数)

      父组件:在调用子组件的地方,自定义的事件名 = { (参数)=> {this.父组件要执行的事件名(参数)}}

    1  // 发送
    2 <p onClick={() => { this.props.toFather(this.state.findlist)}}>点击给父组件传值</p>
    3 
    4 //父组件调用子组件的地方接收
    5 <Find contextobj={this.state.contextobj} toFather={(val) => {this.gettoFather(val)}}></Find>

        gettoFather = (val) => {
           console.log(val, '父组件接收子组件传递过来的数据')
         }

     

    react中兄弟组件之间传值

    https://blog.csdn.net/qq_39290323/article/details/107166396,这个是有问题的,constructor里面是不能直接修改state里面的值的

     

    默认props

       3.2 第二种 class类创建组件 和 this.state

        class创建组件的时候,首先掌握class和类的继承 extends

        在class内部,this表示当前组件的实例对象,

     1 import React from 'react'
     2 // 组件
     3 export default class Home extends React.Component {
     4   constructor() {                //同时创建this(子类本身没有this);所以super(props)的作用就是在父类的构造函数中给props赋值一个对象this.props=props这样就能在它的下面定义你要用到的属性了
     5     // 继承必须调用super,才可以访问this
     6     super()
     7     this.state = {     //  this.state相当于vue中的data() { return {}}, 这个值是可读可写的
     8       massage: "诶若为UR"
     9     }
    10   }
    11   // render() 函数渲染当前组件对应的虚拟dom元素
    12   render() {
    13     return (
    14       //注意,在class内部,this表示当前组件的实例对象
    15       <div>
    16         <div>不知道{this.props.userobj.name}</div>
    17         <h1>{this.state.massage}</h1>
    18       </div>
    19     )
    20   }
    21 }
    22 
    23 
    24 import Home from './Home'
    25 
    26 const userobj = {
    27   name: 'shun',
    28   age: 18
    29 }
    30 
    31 
    32 ReactDOM.render(
    33   <div>
    34     组件
    35     <Home userobj={userobj}></Home>
    36   </div>,
    37   document.getElementById("app"))

     

    props和state的区别:

      #### 函数式组件一般用于静态的渲染,不需要私有数据和声明周期函数

      4. 列表渲染

     1 export default class Listitem extends React.Component {
     2   render() {
     3     return (
     4       <ul>
     5         {this.props.records.map((item) => (
     6           <li key={item.id}>
     7             {item.name + "今年"}
     8             {item.age}
     9           </li>
    10         ))}
    11       </ul>
    12     );
    13   }
    14 }
    innerHtml: "<p>渲染带标签的字符串</p>"
    <p dangerouslySetInnerHTML={{__html: this.state.innerHtml}}></p>

    style样式   less的使用在另一篇随笔中有提到 https://www.cnblogs.com/shun1015/p/13520577.html

        jsx语法中,style写成字符串的形式会报错,在 { } 里面写成对象的形式,对象的key是字符串

    1  <p style={{ color: 'red', fontSize: '18px' }}>列表,下面是子组件</p>
    2 
    3 const stylelist = { color: 'red', fontSize: '18px' }
    4 <p style={stylelist}>列表,下面是子组件</p> 

    react中的css样式作用域

        react中引入外部的样式文件,例如:import '@/style.css',因为没有作用域的概念,组件的所有子组件都会受到这个文件的影响,感觉react的局部样式相比vue要麻烦点,vue可以在style标签上添加scoped,达到使样式作用于当前文件的效果,而react没有,但是react有其他的实现方式,比如css-Modulesstyled-components

      方法一:css-Modules  

        自动为每一个类生成一个哈希值,产生惟一标志,因此避免了类的覆盖

     这里需要配置wepack文件,react项目需要执行npm eject命令暴露出config文件,我这里增加配置如下:

    关于sass和less配置方法是一样的

    关键配置就是 modules: true

    {
                  test: cssModuleRegex,
                  use: getStyleLoaders({
                    importLoaders: 1,
                    modules: true,        // 加这一行代码,css模块化
                    sourceMap: isEnvProduction && shouldUseSourceMap,
                    modules: {
                      getLocalIdent: getCSSModuleLocalIdent,
                    },
                  }),
                }

    当配置好上述步骤后,组件内引入css文件就成了局部的形式,但是引入的css是一个对象

    import cssobj from "@/style/index.scss";
    console.log(cssobj);   

    通过打印这个对象我们发现,我们在css文件里面的只有类选择器和id选择器才会出现在对象里,也就是说,只有类选择器和id选择器才有模块化,只有配置css的模块化之后,才能打印出这个对象,没有配置的时候打印的是个空对象

    所以说我们使用样式的时候 className只需要绑定被转成的哈希值就可以了

    1       <div className={cssobj.listbox}>
    2         <p className={cssobj.title}>子组件列表渲染</p>
    3         <Listitem records={this.state.records}></Listitem>
    4       </div>
    5                 

    注意
    css模块化只针对类选择器和id选择器生效
    css模块化不会将标签选择器模块化

    还有 localIdentname等参数的配置项,自定义生成类名的格式,老版本的已经不适用于webpack4.x版本的项目了,我没有找到具体的配置方法。。。

    :global和:local

      通过:global包裹起来的类名不会被模块化,会变成一个全局的样式,classname直接绑定就好了

      :local包裹起来的类名会被模块化,默认不写也是被模块化,一般不用

    :global(.todolist) {
      color: blue;
    }

      <h2 className="todolist">55555555</h2>
     还可以这样
      <li className={[cssobj.listitem, 'todolist'].join(' ')} key={item.id}>

     事件处理

      react中事件名是小驼峰式命名, onClick={function}

      利用箭头函数的this的指向问题,解决传参

      render() {
        return (
          <div>
    
            <p onClick={function () { alert('pppppppp') }}>点击</p>
    
            <p className={cssobj.click} onClick={this.handleClick}>点击事件,没办法传参啊</p>   // 在构造函数中一个圆形对象的方法,调用另一个圆形对象的方法,使用this
    
            <button onClick={() => { this.clickMe() }}>利用箭头函数,的this指向问题,传参</button>    // 这里利用这里在点击事件中执行一个箭头函数,箭头函数的内部执行事件处理函数
          </div>
        );
      }
      handleClick() {
        alert('react的点击事件')
      }
      clickMe() {
        console.log('点击了我')
      }
    或者写成这样的形式(箭头函数) 匿名函数取了个名字,具名函数,前面调用一个有名字的函数没毛病吧
    clickMe = () => {
        console.log('点击了我')
      }
     

    使用 this.setState()修改state里的数据,本身就是异步的

    这里就很像小程序了 setData(),用法一毛一样

    handleupdata = async () => {
        // this.setState((state) => {
        //   console.log(state)
        //   return { content: '范顺' }
        // })
        await this.setState({ content: '范顺' }, function() {console.log(this.state)})
        await console.log(this.state)
      }

       在使用this.setState(),修改数据的时候,是异步执行的,想拿到state里面更新是的值,用await或者是回调中拿

    react中单向数据流,例如表单元素的value绑定data里的属性,仅仅是只读的,并不能修改输入框里的数据,想要修改输入框里的数据,需要绑定一个事件onChange,通过事件源或者ref属性获取到value并设置给data(手动实现双向绑定)

    而在vue中有v-model这个语法糖,不仅是只读的,当我们修改输入框里的value时,对应绑定data里的数据也会改变,这就是vue的双向绑定(利用了vue的get和set方法)

    例如:获取输入框value的两个方法:1,事件源e  2.ref属性

    refs转发:(表示当前组件真正实例的引用,返回绑定当前属性的元素不能再无状态组价中使用)

     1 render() {
     2     return (
     3         <input type="text" placeholder="请输入姓名" value={this.state.name} onChange={(e) => this.handlechange(e)} ref="mytext" />
     4     )
     5   }
     6   handlechange = (e) => {
     7 
     8     // console.log(e.target.value)
     9     console.log(this.refs.mytext.value)
    10 
    11     this.setState({
    12       // name: e.target.value,
    13       name: this.refs.mytext.value
    14     })
    15   }

     过调用 React.createRef 创建了一个 React ref 并将其赋值给 ref 变量

    constructor(props) {
        super(props)
        this.myref = React.createRef();
    }
    
    render() {
        return (
          <input type="text" ref={myref}/>
          <button onClick={()=>{this.handleclick()}}>点击</button>
      )
    }
    
    handleclick = () => {
      console.log(this.myref.current.value)         //通过变量ref获取到value
    }

     受控组件和非受控组件

      主要针对于表单控件,一个表单元素仅仅设置value为只读,不设置onChange事件就是非受控组件,相反为受控组件

    数据请求axios与 json-server(本地json服务器)

     数据请求axios与 json-server(本地json服务器)

    1.使用json-server 就是把本地的json文件,转成一个可访问的ip地址

      npm i json-server -g

      项目文件夹下新建db.json,然后运行json-server --watch db.json 或者 新建运行命令 npm run json:server,在本地项目的同一个端口下面会出现数据(会遇到问题,慢慢试就好了)

     2. 使用代理请求服务器地址

      和vue一毛一样,在mode_modules/ react-scripts/ config/webpagkDevServer.config.js里面找到proxy, 或者 npm run eject 暴露出config文件夹和script文件夹,在config.webpagkDevServer.config.js里

    1 proxy: {
    2       '/api': {
    3         target: 'https://i.news.qq.com/trpc.qqnews_web.pc_base_srv.base_http_proxy',
    4         changeOrigin: true,   // 是否开启跨域
    5         pathRewrite: {       //重写接口
    6           '^/api': ''
    7         }
    8       }
    9     },

     PrueComponent 

      pruecomponent 创建的组件 提供了一个具有浅比较的 shouldcomponentUpdate 方法,其他和component一致

      在state中存在一个对象的话,记得更新的时候重新赋一个对象,因为还用同一个对象(地址,引用),不会去改变state的值

     感觉 ES6 是为 react 而生的,又像是ES6创造了react......

    //#region 
    //#endregion

          

        

  • 相关阅读:
    英语在线单词、语法检查工具
    Excel操作:导出到Excel并下载到web客户端
    五度圈 Circle of Fifths
    【算法】新浪微博笔试题:找出共有2个以上标签的用户对
    云计算虚拟化可能不是你的菜
    也来聊聊Erlang
    云计算数据存储之购买指南
    聊聊云计算 从OpenStack说起
    WC2022不知道在干什么记
    Silverlight调用WCF服务引用
  • 原文地址:https://www.cnblogs.com/shun1015/p/13489861.html
Copyright © 2020-2023  润新知