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

      

    

原文地址:https://www.cnblogs.com/shun1015/p/13489861.html