类组件 react基础+create-react-app创建项目 Day01

88 阅读12分钟

什么是react

react起源于facebook团队,官网, react是基于V层, 需要周边环境的支持;

react是基于jsx语法, js+xml , 在模板里写js , 属于虚拟dom开发

react特点:

  1. 组件式开发, 为了代码的封装复用
  2. 虚拟dom开发
  3. 虚拟dom diff算法, 把虚拟dom转化成真实dom
  4. react社区完善, 可以开发大型的应用

课程中我们讲的最新的react版本 v18版本

react开发需要依赖2个包

react : 因为 react官网推出混合app(react-native), 所以把react分离成了2个方向, 第一个方向是web(react-dom), 第二个方向是app(react-native)

web和app的共同的核心部分还是保留在react包

开发react web端需要引入: react react-dom

开发react app 端需要引入: react react-native

app应用程序

  • 原生app : 就是安卓和ios端,开发成本比较高,性能是最好的

  • webapp: 就是 h5页面, 通webview浏览器嵌套下, 性能是最差的

  • 混合app: uniapp是多端开发, 可以小程序, 也可以开发混合app,react-native也可以开发混合app

什么是虚拟dom

虚拟dom是一种用javascript对象表示内存中的抽象的dom树,是对真实dom的一个轻量映射, 作用是在前端框架中提供一种高效的dom操作更新机制,可以优化性能和提升用户的体验。

虚拟dom就是一个js对象, 至少包括标签tag,属性attrs,内容children属性

1.React.createElement创建虚拟dom

回顾下 es5创建真实dom的方式

 var dom  = document.createElement('div');
    dom.id = 'app'
    dom.className ='hello'
    dom.innerHTML = '我来了'
    document.body.appendChild(dom)

使用react.createElement创建虚拟dom

  <!-- <div id="app" class="heelo">我来了</div> -->
    <div id="app"></div>
    <script>

    //  es5的方式创建真实dom节点,并插入到body中 复习下
    /* var dom  = document.createElement('div');
    dom.id = 'app'
    dom.className ='hello'
    dom.innerHTML = '我来了'
    document.body.appendChild(dom) */

    //  3个参数: 
    //  1. tag标签 
    //  2.虚拟dom的一些属性
    //  3. 内容
    // React: 来自react.development.js核心包的api
    var xDom =  React.createElement('div',{
        className:'apple',
        style:{color:'red'}
     },'hello react');

     // 虚拟dom 如何渲染在页面中
    //  ReactDOM: 来自react-dom.development.js的api
    let root =  ReactDOM.createRoot(document.getElementById('app'));  
    // 使用ReactDOM.createRoot创建根节点
    root.render(xDom);
    // 通过render 方法把虚拟dom转化成真实dom渲染在模板中

2.使用jsx创建虚拟dom

babel包一般用来把es6,es7语法转化成浏览器可以识别的es5语言,同时babel也内置了对jsx语法的支持

jsx = javascript (js) + XML(html) ,可以在模板中写js语言

jsx的特点:

1.开发代码更简洁

2.性能上更好, 执行代码的速度更快

需要引入babel包

    <script  src="https://unpkg.com/react@18/umd/react.development.js"></script>
    <script  src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
    <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
  <div id="app"></div>
    <!-- text/babel 用来支持jsx的语法 -->
    <script type="text/babel">
        var str = 'hello react';
        //  background-color
        var  vDOM = <div className='hello' style={{color:'red',backgroundColor:'blue'}}> {str}</div>;
        let root = ReactDOM.createRoot(document.getElementById('app'));
        root.render(vDOM)

    </script>

注意点:

1.需要依赖babel包,在script上条件type="text/babel"

2.react,jsx中使用模板渲染标志是{}

3.style样式本来是有多个属性的, 是以对象的对象的形式赋值, style标签外层的{}是react的语法,第二个{}是style对象形式

4.style中的样式,如果是烤串 式 background-color 统一写成 小驼峰 backgroundColor

5.使用外部样式class,jsx中统一使用className

jsx逻辑运算处理

加,减,乘,除 ,||, && , 三目元算符

react中没有指令, 需要通过逻辑运算去控制节点的显示和隐藏等操作

   var num1 = 1;
       var num2 = 3;
        var str1 = '';
        var isBool = false;
        var vDOM = <div>
                    演示: 
                    <p> {num1+num2}  </p>
                    <p>{num2-num1}</p>
                    <p> {num1 *num2 }</p>
                    <p> {num2 / num1 }</p>
                    <p> {str1 || '临时的内容'}</p>
                    <p>
                        {isBool && <div className="demo">我们在学react</div>}
                    </p>
                    <p> {isBool ? '苹果' :'香蕉' }  </p>
                    <p> {JSON.stringify(isBool)} </p>
                </div>;
            
                let root = ReactDOM.createRoot(document.getElementById('app'));
        root.render(vDOM)

boolean值 不能直接在模板渲染, 如果你想打印boolean值来测试, 可以使用{JSON.stringify(isBool) }

jsx数据动态渲染

实践需求:

var names = ['苹果','香蕉','桃子'];

利用jsx的语法把数组names 解析成列表进行渲染

列表结构<ul><li>香蕉</li></ul>

总结:

1.jsx中不能直接渲染对象,但是可以直接渲染数组

2.如果需要把数组中的数据渲染在模板, 需要通过map循环,处理成我们想要的结构,然后在模板中渲染

3.map循环的时候, 返回的虚拟dom标签必须有一个唯一的key, 提高页面的性能

<div id="app"></div>
    <script type="text/babel">
        // var names = ['苹果','香蕉','桃子']; 
        var names = [{name:'苹果',price:20},{name:'香蕉',price:10},{name:'桃子',price:50}]; 
        var obj = {name:'alice'};
        var list = names.map((item,index)=>{
            return <li key={index}>{item.name}   --- {item.price }</li>
        })
        var vDOM = <div>
                hello
                <ul>
                   {list}
                </ul>
            </div>;

        var root = ReactDOM.createRoot(document.getElementById('app'));
        root.render(vDOM); 

组件的概念

react和vue一样, 都是组件式开发,组件式开发是为了提高开发效率和提高组件的可复用性, 方便后期维护和扩展等;

react中定义组件有2种方式:

react版本v16.8之前, 一般都使用类组件, 比较强大, 但是官网比较推荐使用函数组件

1.类组件: class

2.函数式组件: function

1.复习class类

  <script>
        class People {
            static school = '蜗牛';
            constructor(name,age){
                // 实例属性
                this.username = name;
                this.age = age;
            }
            sayHello(){
                console.log(this);
                // this  People类的实例化对象
                console.log('hello,你好');
            }
            singFun=()=>{
                console.log('==========');
                console.log(this);
                console.log('唱歌');
            }
        }

var p1  = new  People('xiaohong',20) ;
// 每次实例化一个对象,都是需要先走constructor
// 访问静态属性直接通过类 
console.log(People.school);
// p1.sayHello();
// p1.sing();
var sayTest = p1.sayHello;
sayTest()

var singTest = p1.singFun;
singTest()

总结:

1.类的名字首字母大写

2.类中的静态属性和静态方法使用关键字static 定义,可以直接通 类名.静态属性 访问

3.在类中定义方法的, 一般情况下指向类的实例化对象

4.类中定义的普通方法可以改变this的指向, 但是类中的箭头函数永远指向类的实例化对象

类中普通方法 通过实例化对象得到后赋值给其他变量后, this为什么变成undefined

  1. 赋值方法后,是依赖上下文环境的,正常情况下是指向window对象, 但是class类中自动开启了严格模式, 所以是undefined

2.在类中定义普通函数和箭头函数的区别

1.类中定义的箭头函数,没有挂载在类组件的原型上, 在类继承中, 箭头函数也被继承,但不是被挂载在原型上

2.一般情况下类中的this指向实例,类中方法实例调用的话,类方法中this就指向实例对象

3.在JavaScript中,类中的普通方法被存储在类的原型对象中。当你将一个方法复制给一个变量后再执行,方法中的this可以改变。这是因为this在JavaScript中是动态绑定的,它的值取决于函数被调用的上下文。

3.但是把类中的方法,赋值给变量之后再调用就相当于自调用了,就不是实例调用了。赋值方法this就是指向window,但是类中的方法是自动开启局部严格模式了,所以赋值方法this最终是undefined

this会根据是否是严格模式而指向undefined或者全局环境

注:ES6 的class内部默认为严格模式

4.类中的普通函数可以通过bind, call, apply改变函数的this指向, 箭头函数不能通过bind, call,apply改变他的this指向,类中的箭头函数this 一直都是指向类的实例化对象的

3.继承

使用关键字extends实现继承, 必须在constructor有一个super方法

class Teacher extends People {
    constructor(name,age,country){
        super(name,age);
        this.country = country;
    }
    teach(){
        console.log('老师教书');
    }
}

var tea1 = new Teacher('王老师','30','中国');
tea1.teach();

实现继承的时候, constructor是必须的, 但是如果不写,es6的语法会自动帮你添加,

那如果类有变量需要传去, 可以不省略constructor, 如果没有变量, 建议使用省略constructor的形式去写

简写的形式

class Teacher extends People {
    student = '小王'
    teach(){
        console.log('老师教书');
        console.log(this.student);
    }
}

4.类中定义计算器属性

get fullname(){
        return this.username  + ' ' + this.lastname;
 }

在实例化对象中直接访问 , 计算器属性中, 只有依赖的数据发生了改变, 计算器属性的值会重新计算

react中定义类组件

  // 创建一个Header类组件
        class Header extends React.Component {
            // constructor(){
            //     super();
            //     this.username = 'xiaohua'
            // }
            // 简写的形式
            username = 'xiaohua'
            render(){
                return <div> 我是header组件 {this.username}  </div>
            }
        }   
        var root = ReactDOM.createRoot(document.getElementById('app'));
        root.render(<Header />)

总结:

1.类组件的首字母大写

2.类组件中必须有一个render方法,比例必须有一个return 返回虚拟dom

3.而且return的虚拟dom必须有一个根节点

定类组件中的内部数据

通过this.sate = 组件内部数据

 constructor(){
                super();
                // this.username = 'xiaohua'
                // 组件内部数据
                this.state = {
                    username:'xiaohua',
                    age:20
                }
            }

简写的形式, 直接在类组件中定义state

state = {
     username:'xiaohua',
      age:20
 }

在模板中访问类组件中的数据

this.state.username

修改类组件中数据使用setState

setState是一个异步函数, 只要执行了setState, 就会再次调用render函数,引发模板的重新渲染

方式一:
this.setState({
     username:'小刚'
  })
方式二:
setState 可以接收2个参数,
第一个函数,修改数据后, 通过return返回
第二个回调 可以获取修改后的最新值
this.setState((prev)=>{
          // console.log(prev);  // 组件内部数据
          return {
               username:'小刚'
         }
  },()=>{
        console.log(this.state.username);
  })

事件绑定使用onClick

<button onClick={this.updateName}>修改name</button>

注意: onClick后 必须跟着一个函数, 为了一劳永逸的解决函数this指向的问题, 我们建议大家使用箭头函数定义

事件绑定传参方式

方式一: data-烤串的形式传参

 <button data-username='小刚' onClick={this.updateName}>修改name</button>

获取参数, 通过ev事件对象获取

 updateName = (ev)=>{
      console.log(ev.currentTarget.dataset.username);  
 }

方式二:使用箭头函数的方式传参

 <button onClick={()=>this.updateName('小红')}>修改name</button>

获取参数

 updateName = (name)=>{
 	this.setState({
 		username:name
 	})
 }

推荐第二种箭头函数方式传参

类组件中props传值

使用props传值

<Header title="蜗牛" bg="red" />

类组件中获取props, 在constructor中使用props接收

 constructor(props){
                // 组件内部数据
                super(props);
                console.log(this.props);
                this.state = {
                    username:'xiaohua',
                    age:20
                }
 }

或者使用简写的方式, 直接不用写 , 直接在模板中通过 {this.props.属性名} 获取

补充:

<Header title="蜗牛" bg="red" height="80px" />

 render(){
                const {title,bg,height} = this.props;
                return <div style={{backgroundColor:bg, height:height}}> 
                    <p>
                         props中的数据  <br/>
                         {this.props.title}
                    </p>
               </div>
 }

定义默认属性: 直接关键字static defaultProps定义, 以对象的形式, 可以定义多个默认属性

static defaultProps = {
      height:'100px',
      bg:'blue'
 }
  1. 在模板渲染中, 建议大家使用解构方式 拿到state中数据 , 或者props中的数据,再进行数据的渲染

搭建react环境

使用官方create-react-app, 基于webpack的

npx create-react-app 项目名称  

总结:

  1. npx这个命令无需安装, 直接使用,node安装后, 自动就有了
  2. npx安装的目的是每次创建项目都使用最新的 create-react-app的版本,并不需要在本地安装这个create-react-app

下载插件:

在实际开发过程中,由于这些组件和函数组件它的结构都是固定的,所以可以使用一些插件将其生成出来

image-20230206115912857

使用rcc生成类组件,使用rfc生成函数组件

项目目录结构

src:存放开发的资源

---components:代表组件

---pages/views:代表页面(一般跟路由相关的页面)

---utils:存放工具

index.js:代表项目入口文件,启动项目首先加载这个文件

App.js这个文件代表项目根组件。默认在Index.js被加载

React中组件有两种后缀:以js结尾的文件,jsx结尾文件(推荐)

yarn包管理工具

yarn包管理管局,类似npm, 出自facebook团队

可以缓存你已经下载过的包,哪怕是在离线的情况下, 也可以下载你之前下载过的包

1: 快速 , 因为从缓存直接读取

2 :安全 ,可靠

参考官方文档yarn.bootcss.com/

yarn的安装

npm install yarn -g

查看yarn的版本号

yarn -v   // 或者 yarn --version

初始化 一个包文件package.json

yarn init -y

通过yarn安装包

yarn add 包的名字   // 默认安装最新的包
yarn add 包的名字@2     //是定版本安装

不管你用npm 还是yarn ,如果不指定版本号, 安装都是最新的版本

删除你安装的包

yarn remove 包的名字

全局安装某一个包

yarn global add 包的名字

全局删除某一个包

yarn global remove 包的名字

设置镜像

yarn config set registry http://registry.npm.taobao.org
yarn config set sass_binary_site http://cdn.npm.taobao.org/dist/node-sass

整体安装package.json里的包

yarn  或者 yarn install

检查环境变量配置

右键电脑 - 》 属性-》点击高级系统设置-》点击环境变量-》点击系统变量的path,然后进行配置

nvm切换node版本号

nvm 默认安装在c盘, 不要选其他的盘

走入企业后 , 第一件时间是和你同事核对项目node的版本号, node -v, 至少大版本好要保持一致, 然后在安装项目的依赖包

如果你同时开发多个项目, 2个项目是依赖不同的node版本号

A项目: node版本18

B项目: node版本16

比较简便的方式通过nvm管理node版本号

www.jianshu.com/p/e22349233…

如果有项目使用不同的node, 可以使用nvm来切换node版本号

nvm -v  // 查看nvm版本号
nvm install 18.16.0    // node的版本号要确保存在的
nvm ls    // 查看本地安装的所有node版本
nvm use 18.16.0    //使用某一个node版本
node  -v   // 查看当前使用的node版本

安装scss预处理

create-react-app安装的项目 ,已经内置了scss的配置, 你不需要配置,只需要安装node-sass sass-loader, 如果你要配置less,就会稍微麻烦点, 因为create-react-app没有内置less的配置,所以这里选择scss

yarn add node-sass sass-loader -D   //安装在开发包

node-sass安装不上可以这样安装

npm install sass node-sass@npm:sass

create-react-app创建的项目, 已经内置babel的配置, 所以我们新建项目的时候, 可以直接使用jsx