React基础篇

1. React基础知识

1.1注意事项:

  1. jsx中 写注释**:推荐使用{ /* 这是注释 */ }**

  2. jsx中的元素添加class类名

    • 使用className 来替代 class
    • htmlFor替换label的for属性
  3. JSX创建DOM的时候,所有的节点,必须有唯一的根元素进行包裹;

  4. jsx语法中,标签必须 成对出现,如果是单标签,则必须自闭和!

  5. 当 编译引擎,在编译JSX代码的时候,如果遇到了<那么就把它当作 HTML代码去编译,如果遇到了 {} 就把 花括号内部的代码当作 普通JS代码去编译;

  6. React中创建组件(组件的名称首字母必须是大写)

  7. 不论是 class 还是 普通的function创建的组件,它们的props都是只读的
  8. 在 render 函数中不能使用 setState

setState会触发 render 函数的执行,如果在 render 函数中,又调用了setState,则会进入死循环!

1.2手动创建:基本的webpack4.x项目

  1. 首先新建项目文件夹 webpack-base
  2. 在项目根目录:运行npm init -y 快速初始化项目
  3. 在项目根目录:创建src源代码目录和dist产品目录和test目录

src目录下:

  • 创建 index.html
  • 创建 index.js
  1. 使用 cnpm 安装 webpack ,
运行:cnpm i webpack webpack-cli -D ;安装 webpack

运行:cnpm i webpack-dev-server -D  ;开启 实时打包编译

运行:cnpm i html-webpack-plugin -D

运行:cnpm i url-loader file-loader -D     解析图片

运行:cnpm i style-loader css-loader -D   处理第三方样式表

运行:cnpm i sass-loader node-sass -D     处理自己的样式表

运行:cnpm i @babel/core babel-loader @babel/plugin-transform-runtime -D

运行:cnpm i @babel/preset-env @babel/preset-stage-0 -D

运行:cnpm i @babel/preset-react -D     安装能够识别转换jsx语法的包

运行:cnpm i antd -S   安装 AntDesign 组件库

运行cnpm i babel-plugin-import -D  开发环境安装按需导入的babel插件

如何安装 cnpm: 全局运行 npm i cnpm -g

注意:webpack 4.x提供了 约定大于配置的概念;目的是为了尽量减少 配置文件的体积;

  • 默认约定了:
  • 打包的入口是src -> index.js
  • 打包的输出文件是dist -> main.js
  • webpack4.x 中 新增了 mode 选项(为必选项),可选的值为:developmentproduction;
  1. 在项目根目录/新建 webpack.config.js
const path = require('path')
const HtmlPlugin = require('html-webpack-plugin')
const htmlPlugin = new HtmlPlugin({
template: path.join(__dirname, './src/index.html'), // 指定模板文件
filename: 'index.html' // 指定内存中生成的首页的名称
})

// 导入webpack的配置对象
module.exports = {
// 必须要有mode属性:有两个可选值  development   production
mode: 'development',
// 注意:默认4.x 的webpack中,约定了打包的入口是 src->index.js 出口是dist->main.js
// 插件节点
plugins: [
  htmlPlugin
],
module: {
  rules: [
      { test: /\.jpg|png|gif|bmp|webp$/, use: 'url-loader' }, // 处理图片
      { test: /\.ttf|woff|woff2|eot|svg$/, use: 'url-loader' }, // 处理字体文件
      { test: /\.css$/i, use: ['style-loader', 'css-loader'] }, // 处理普通css样式表
      {
          test: /\.scss$/,
          use: [
              { loader: "style-loader" },
              {
                  loader: "css-loader",
                  options: {
                      modules: {
                          localIdentName: "[path][name]-[local]-[hash:5]"
                      }
                  }
              }],   //打包处理css样式表的第三方loader
      },
      { test: /\.js|jsx$/, use: 'babel-loader', exclude: /node_modules/ } // babel-loader
  ]
},
resolve: {
  extensions: ['.js', '.jsx', '.json'], // 可省略的扩展名
  alias: {
      '@': path.join(__dirname, './src') // 设置别名
  }
}
}
  1. 在项目根目录/新建 .babelrc文件
{
"presets": [
  "@babel/preset-env",
  "@babel/preset-react"
],
"plugins": [
  "@babel/plugin-transform-runtime",
  ["import", { "libraryName": "antd", "libraryDirectory": "es", "style": "css" }]
]
}

1.3设置样式

1.3.1多个className怎么设置??
<p className={title,' test'}>内容1</p>

<p className={[title,'test'].join(' ')}>内容2</p>

1.3…2使用普通的 style 样式
注意:在 JSX语法中,如果想写 行内样式了,不能 为style 设置 字符串的值
而是应该 style={ {color: 'red', fontWeight: 200} }
在行内样式中,如果是 数值类型的样式;则可以不用引号包裹;
如果是字符串类型的样式值,必须用 引号包裹
<h1 style={ {color: 'red', fontWeight: 200} }></h1>
1.3.3启用css-modules

使用css样式表美化组件

  • src / 新建css文件夹 / cmtList.css文件
  • css 模块化,只针对 类选择器 和 Id选择器 生效
  • css 模块化,不会将标签选择器模块化
.title {
	color: red;
}
  • 运行cnpm i style-loader css-loader -D
  • 修改 webpack.config.js这个配置文件,为.css后缀名的样式表 启用CSS 模块化
module: {
rules: [
 { test: /\.css$/, use: ['style-loader', 'css-loader?modules'] }
]
}
  • 在需要的组件中,import导入样式表,并接收模块化的 CSS样式对象:
import cssObj from '@/css/CmtList.css' 
  • 在需要的HTML标签上,使用className指定模块化的样式:
<h1 className={cssObj.title}>评论列表组件</h1>
1.3.4使用localIdentName自定义生成的类名格式

可选的参数有:

  • [path] 表示样式表 相对于项目根目录 所在路径
  • [name] 表示 样式表文件名称
  • [local] 表示样式的类名定义名称
  • [hash:length] 表示32位的hash值(只要 hash值 < 32,可以任意取)
修改 webpack.config.js这个配置文件(以此为准)
module: {   //所有第三方模块的配置规则
   rules: [  //第三方匹配规则
       {
           test: /\.css$/,
           use: [
               {loader: "style-loader"}, 
               {loader: "css-loader",
                options: {
                   modules: {
                       localIdentName: "[path][name]-[local]-[hash:5]"
                   }
                }
               }],   //打包处理css样式表的第三方loader
       }
   ]
},
1.3.5使用 :local():global()
  • :local()`包裹的类名,是被模块化的类名,只能通过className={cssObj.类名}来使用

同时,:local默认可以不写,这样,默认在样式表中定义的类名,都是被模块化的类名;

:local(.title) {
	color: red;
}
  • :global()包裹的类名,是全局生效的,不会被 css-modules 控制,定义的类名是什么,就是使用定义的类名className="类名"
:global(.title) {
	color: red;
}
1.3.6在项目中启用模块化并同时使用bootstrap

运行: cnpm i bootstrap@3.3.7 -S cnpm i url-loader -D cnpm i file-loader -D

在需要的组件中,import导入样式表,并接收模块化的CSS样式对象:

如果在引用某个包的时候,这个包被安装到了node_modules目录中,

则可以省略 node_modules 这一层目录,直接以包名开始引入自己的模块或样式表

import 'bootstrap/dist/css/bootstrap.css' 

修改 webpack.config.js这个配置文件,打包处理字体文件的 loader

module: {
rules: [
  { test: /\.ttf|woff|woff2|eot|svg$/, use: 'url-loader' }
]
}
1.3.7在项目中为 scss文件 或者 less文件启用模块化

自己规定:

  • 把 自己的样式表,定义为 .scss 文件 或者 .less 文件;启用模块化即可;
  • 第三方的样式表,还是 以 .css 结尾,这样我们不要为普通的 .css启用模块化

运行cnpm i sass-loader node-sass -D 安装能够解析scss文件的loader

修改 webpack.config.js这个配置文件,打包处理scss文件的 loader

module: {
rules: [
{
   test: /\.scss$/,
   use: [
       { loader: "style-loader" },
       {
           loader: "css-loader",
           options: {
           modules: {
           	localIdentName: "[path][name]-[local]-[hash:5]"
           }
       }
   }],   //打包处理css样式表的第三方loader
}
]
}

使用方法:

在需要的组件中,import导入样式表,并接收模块化的 CSS样式对象:

import 'bootstrap/dist/css/bootstrap.css' 

import cssObj from '@/css/CmtList.scss' 
<button className="btn btn-primary">按钮</button>

2.在项目中使用 react

  1. 运行 cnpm i react react-dom -S 安装包

    • react: 专门用于创建组件和虚拟DOM的,同时组件的生命周期都在这个包中
    • react-dom: 专门进行DOM操作的,最主要的应用场景,就是ReactDOM.render()

    运行:npm run dev启动项目

  2. index.html页面中,创建容器:

    <!-- 容器,将来,使用 React 创建的虚拟DOM元素,都会被渲染到这个指定的容器中 -->
    <div id="app"></div>
    
  3. index.js页面中

    • 导入包:

      import React from 'react'
      import ReactDOM from 'react-dom'
      
    • 创建虚拟DOM元素

      这是 创建虚拟DOM元素的API

      你比四环多一环

      第一个参数: 字符串类型的参数,表示要创建的标签的名称
      第二个参数:对象类型的参数, 表示 创建的元素的属性节点

      第三个参数: 子节点

      const myh1 = React.createElement('h1', { title: '啊,五环', id: 'myh1' }, '你比四环多一环')
      
    • 渲染虚拟DOM元素

      参数1: 表示要渲染的虚拟DOM对象
      参数2: 指定容器,注意:这里不能直接放 容器元素的Id字符串,需要放一个容器的DOM对象

      ReactDOM.render(myh1, document.getElementById('app'))
      

    index.js页面(实现虚拟DOM嵌套:mydiv > myh1

    import React from 'react'
    import ReactDOM from 'react-dom'
    
    const myh1 = React.createElement('h1', { title: '啊,五环', id: 'myh1' }, '你比四环多一环')
    
    const mydiv = React.createElement('h1', { title: '啊,五环', id: 'myh1' }, '你比四环多一环',myh1)
    
    ReactDOM.render(mydiv, document.getElementById('app'))
    

3. JSX语法

index.js页面中(项目中的写法

const mydiv = <div id="mydiv" title="div aaa">
    这是一个div元素
	<h1>这是一个大大的H1</h1>
</div>

什么是JSX语法:就是符合xml规范的JS语法;(语法格式相对来说,要比HTML严谨很多)

3.1如何启用jsx语法?

  • 安装 babel 插件

    • 运行cnpm i @babel/core babel-loader @babel/plugin-transform-runtime -D
    • 运行cnpm i @babel/preset-env @babel/preset-stage-0 -D
  • 安装能够识别转换jsx语法的包

    • 运行cnpm i @babel/preset-react -D
  • src目录平级,添加 .babelrc 配置文件

    {
        "presets": [
            "@babel/preset-env",
            "@babel/preset-react"
        ],
        "plugins": [
            "@babel/plugin-transform-runtime"
        ]
    }
    
  • webpack.config.js页面中,添加babel-loader配置项:

    module: { //要打包的第三方模块
        rules: [
          { test: /\.js|jsx$/, use: 'babel-loader', exclude: /node_modules/ }
        ]
    }
    

jsx语法的本质:并不是直接把jsx渲染到页面上,而是 内部先转换成了 createElement形式,再渲染的

jsx 中混合写入js 表达式:在 jsx语法中,要把JS代码写到 { }

  • 渲染数字
  • 渲染字符串
  • 渲染布尔值
  • 为属性绑定值
  • 渲染jsx元素
  • 渲染jsx元素数组
let aa = 12
let title = "999"
let body = false
const h1 = <h1>的骄傲开发</h1>
const array = [
	<h1>的骄傲开22</h1>
	<h1>的骄傲开11</h1>
]

ReactDOM.render(<div>
{a + 2}
{body?'条件为真':'条件为假'}
<p title={title}>这是p标签</p>
{array}
{title}
</div>, document.getElementById('app'))
  • 将普通字符串数组,转为jsx数组并渲染到页面上【两种方案】

    • 方法1:
    const arrstr = ["11","22","33"]
    
    // 定义一个空数组,将来用来存放  名称 标签
    const newArr = []
    arrstr.forEach(item=>{
    	const temp = <h5 key={item}>{item}</h5>
    	newArr.push(temp)
    }
    ReactDOM.render(<div>
    	{newArr}
    </div>, document.getElementById('app'))
    
    • 方法2
    const arrstr = ["11","22","33"]
    
    ReactDOM.render(<div>
    	{arrstr.map(item=>{
    		return <h3 key={item}>{item}</h3>
    	})}
    </div>, document.getElementById('app'))
    

4.将组件封装到单独的文件components中

例如:新建src/components/Hello.jsx

  • 方法1:使用 function 创建组件
import React from 'react'

export default function Hello () { 
	// return null 
	return <div>Hello 组件</div>
}
  • 方法2:使用 class 关键字 创建组件
import React from 'react'

export default class Movie extends React.Component {
 constructor(){
    super()
    
    // 组件私有数据
    this.state = {
        
    }
}

 render(){	
     return <div>内容</div>
 }
 
}

然后在index.js页面中,引入组件

import Hello from './components/Hello.jsx'

在导入组件的时候,如何省略组件的.jsx后缀名:

  • 在导入组件的时候,配置和使用@路径符号
// 打开 webpack.config.js ,并在导出的配置对象中,新增 如下节点:
resolve: {
extensions: ['.js', '.jsx', '.json'], // 表示,这几个文件的后缀名,可以省略不写
alias: {
  '@': path.join(__dirname, './src')
}
}

以上配置完成后,可以使用下面的引入方式:

index.js页面中,引入组件

import Hello from '@/components/Hello'

5.创建组件的方式:

第1种 - 使用构造函数来创建组件

使用构造函数来创建组件,然后直接把组件的名称 以标签的形式,丢到页面上即可。

如果要接收外界传递的数据,需要在构造函数的参数列表中使用props来接收;

必须要向外return一个合法的JSX创建的虚拟DOM;

如果在一个组件中 return 一个 null 则表示此组件是空的 什么都不会渲染
  • 创建组件:

    import React from 'react'
    import ReactDOM from 'react-dom'
    
    function Hello () { 
    	// return null 
    	return <div>Hello 组件</div>
    }
    
    ReactDOM.render(<div>
    	<Hello></Hello>
    </div>, document.getElementById('app'))
    
  • 为组件传递数据(2种方法)

    注意:不论是Vue还是 React,组件中的 props 永远都是只读的;不能被重新赋值;

    import React from 'react'
    import ReactDOM from 'react-dom'
    
    const dog = {
        name: '大黄',
        age: 12,
        gender: '雄'
    }
    
    // 在构造函数中,使用 props 形参,接收外界 传递过来的数据
    function Hello(props) {
      // props.name = 'zs'
      console.log(props)
     
      return <div>这是 Hello 组件 --- {props.name} --- {props.age} --- {props.gender}</div>
    }
    
    function Hello11(props) {
      // props.name = 'zs'
      console.log(props)
     
      return <div>这是 Hello 组件 --- {props.name} --- {props.age} --- {props.gender}</div>
    }
    
    
    ReactDOM.render(<div>
    	<Hello name={dog.name} age={dog.age} gender={dog.gender}></Hello>
        <Hello11 {...dog}></Hello11>
    </div>, document.getElementById('app'))
    

第2种 - 使用 class 关键字来创建组件

index.js页面基本结构:

import React from 'react'
import ReactDOM from 'react-dom'

// 导入 评论项 子组件
import CmtItem from '@/components/CmtItem'

class Movie extends React.Component {
    constructor(){
       super()
       
       // 组件私有数据
       this.state = {
           
       }
   }
 
    render(){	
        return <div>内容</div>
    }
    
}

ReactDOM.render(<div>
    <Movie></Movie>
</div>, document.getElementById('app'))

如果要使用 class 定义组件,必须 让自己的组件,继承自React.Component

在组件内部,必须有 render 函数,作用:渲染当前组件对应的 虚拟DOM结构

render 函数中,必须 返回合法的 JSX虚拟DOM结构

然后直接把组件的名称 以标签的形式,丢到页面上即可

这里的Movie标签 其实就是Movie类的一个实例
拓展:render 是 class 的实例方法
代码示例:
  • 使用 class 关键字来创建组件
  • 为class创建的组件传递props参数并直接使用
  1. 在 class 关键字创建的组件中,如果想使用外界传递过来的props参数,不需接收;

直接通过this.props.属性 访问即可

  1. 在class组件内部,this表示当前组件的实例对象
  2. 不论是 class 还是 普通的function创建的组件,它们的props都是只读的

而 在 class 创建的组件中,this.state.属性 都是可读可写的

  1. 语法规范:在子类中,this只能放在super之后使用
this.state = {};相当于vue中的data(){return { }}
import React from 'react'
import ReactDOM from 'react-dom'

class Movie extends React.Component {
    constructor(name,age){
       super(name,age)
        
       // 组件私有数据
       this.state = {
           msg: '我是 class 创建的 Movie组件'
       }
   }
 
    render(){	
        // this.props.name = 'lisi'(因为props是只读的,所以后台会报错)
        
        this.state.msg = 'msg的值被我修改了'
        
        return <div>这是 class 创建的组件--{this.props.name}--{this.state.msg}</div>
    }
    
}

const user = {
    name: 'zs',
    age: 23,
    gender: '男'
}

ReactDOM.render(<div>
    <Movie name={user.name} age={user.age}></Movie>
    <Movie {...user}></Movie>
</div>, document.getElementById('app'))

ES6中 class 关键字,是实现面向对象编程的新形式;

注意事项:

  1. 在 class 的 { } 区间内,只能写 构造器 静态属性和静态方法、实例方法
  2. class 关键字内部,还是用原来的配方实现的;所以说 我们把 class 关键字 称作 语法糖。
// 原来的配方
function Person(name,age) {
 this.name = name
 this.age = age
}

// 静态属性
Person.info = 'aaaa'

Person.prototype.say = function() {
 console.log('这是Person的实例方法')
}
// 静态方法
Person.show = function() {
  console.log('这是Person的静态方法')
}

const p1 = new Person('王多多',18)
console.log(p1)
p1.say()
Person.show()

6.了解ES6中 class 关键字的使用

  1. class 中 constructor 的基本使用
  2. 实例属性和实例方法
    • 通过new出来的实例,访问到的属性,叫做实例属性
  3. 静态属性和静态方法
    • 通过构造函数直接访问到的属性,叫做静态属性。
    • 在 class 内部 通过 static 修饰的属性,就是静态属性
代码示例:

在components/新建Animal.jsx页面,然后在index.js中引入

import Animal from '@/components/Animal

Animal.jsx页面中

import React from 'react'
import ReactDOM from 'react-dom'

// 创建了一个动物类
class Animal {
	// 这是类中的  构造器
	// 每一个类中,都有一个构造器,如果我们程序员没有手动指定构造器,那么可以认为类内部有个隐形的、看不见的、空构造器,类似于 constructor(){}
	// 构造器的作用:就是每当 new 这个类的时候,必然会优先执行构造器中的代码
    constructor(name,age){
        // 实例属性
        this.name = name
        this.age = age
    }
    // 在 class 内部 通过 static 修饰的属性,就是静态属性
    static info = '寂寞中的旅途'
	
	//实例方法:
	jiao(){
        console.log('这是实例方法')
    }
	// 静态方法
	static show(){
         console.log('这是静态方法')
    }
}

const a1 = new Animal('大黄',13)
console.log(a1)
console.log(a1.name)
console.log(a1.age)
console.log(Animal.info)
a1.jiao()
Animal.show()

7.使用 extends 关键字实现继承

在 class 类中,可以使用 extends 关键字,实现 子类继承父类;语法:class 子类 extends 父类 {}

可以把父类 理解成原型对象 prototype

  • 使用 extends 关键字实现子类继承父类
  • 子类访问父类上的实例方法和实例属性
  • constructor 构造器中 super函数的使用(如果子类中不写constructor 构造器,默认会传递数据
  • 为子类挂载独有的实例属性和方法

问题1:为什么一定要在 constructor 中 调用super()

答:因为 如果一个子类,通过 extends 关键字继承了父类,那么 在 子类的 constructor 构造函数中

​ 必须优先调用一下super()

问题2:super是什么?

答:super是一个函数,而且它是父类的构造器;子类中的super,

​ 其实就是父类中 constructor 构造器的一个引用

问题3:为什么调用了super() 之后,a1实例的name和age变成了undefined ?

答:因为没有传递name和age

代码示例:
import React from 'react'
import ReactDOM from 'react-dom'

class Person {
constructor(name,age){
  // 实例属性
 this.name = name
  this.age = age
}
// 在 class 内部 通过 static 修饰的属性,就是静态属性
static info = '寂寞中的旅途'
	
	//实例方法:
	sayHello(){
  console.log('这是实例方法')
}
	// 静态方法
	static show(){
   console.log('这是静态方法')
}
}


class American extends Person {
constructor(name,age){
 super(name,age)
}
}

const a1 = new American('jack',13)
console.log(a1)
console.log(a1.name,a1.age)
a1.sayHello()


class Chinese extends Person {
 constructor(name,age,idCard){
    super(name,age)
    // 语法规范:在子类中,this只能放在super之后使用
    this.idCard = idCard
}
}

const c1 = new Chinese('李四',13,122346546)
console.log(c1)
console.log(c1.name,c1.age)
c1.sayHello()

8.两种创建组件方式的对比

注意:使用 class 关键字创建的组件,有自己的私有数据(this.state)和生命周期
注意:使用 function 创建的组件,只有 props,没有自己的私有数据和生命周期
有状态组件和无状态组件之间的本质区别就是:有无state属性和 生命周期函数
  1. 构造函数创建出来的组件:叫做“无状态组件”
  2. class关键字创建出来的组件:叫做“有状态组件”
  3. 什么情况下使用 有状态组件 或者 无状态组件 呢?
如果一个组件需要有自己的私有数据,推荐使用 有状态组件

如果一个组件不需要有自己的私有数据,推荐使用 无状态组件

React官方说:无状态组件,由于没有自己的state和生命周期,所以运行效率会比有状态组件稍微高一些

  1. 组件中的props 和 state/data 之间的区别
  • props 中的数据都是外界传递过来的
  • state/data 中的数据,都是组件私有的;(通过Ajax获取的数据,一般都是私有数据)
  • props 中的数据都是只读的;不能重新赋值
  • state/data 中的数据,都是可读可写的
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

落花流雨

你的鼓励将是我创作的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值