1 Star 0 Fork 0

抹上一抹凉 / react_site

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README

React简介

教程参考自啊B的这个视频 用于构建用户界面的JavaScript库。(只关注视图,只管界面的呈现)。 是一个将数据渲染为HTML视图的开源JavaScript库。

React特点

  1. 采用组件化模式、声明式编码,提高开发效率以及组件复用率。
  2. 在React Native中可以使用React语法进行移动端开发。
  3. 使用虚拟DOM + 优秀的Diffing算法,尽量减少与真实DOM的交互。 原生JS实现 原生JS如果要新增数据,不能复用之前的数据,只会全部重新生成。 React实现 React如果要新增数据,会跟之前的虚拟DOM进行比较,如果数据跟更改之前的数据一致,不会产生新的真实DOM。

学习React之前需要掌握的JS基础知识

  1. 判断this的指向
  2. class(类)
  3. ES6语法规范
  4. npm包管理器
  5. 原型、原型链
  6. 数组的常用方法
  7. 模块化

React入门

  1. babel ES6转ES5、import以及将jsx转成js;
  2. JSX可以避免创建虚拟DOM无限套娃的情况,JSX创建虚拟DOM就是js创建虚拟ODM的语法糖;

虚拟DOM

  1. 本质是Object类型的对象(一般对象);
  2. 虚拟DOM比较“轻”(属性比较少),因为虚拟DOM是React内部使用,无需真实DOM上那么多的属性;
  3. 虚拟DOM最终会被React转化为真实DOM,呈现在页面上。

JSX

    全程JavaScript XML。XML早期用于存储和传输数据,后期被JSON代替。类似如下图

XML JSON对比

语法规则

  1. 定义虚拟DOM时,不要写引号;
  2. 标签中混入JS表达式时,使用花括号({})引入;
  3. 样式的类名指定不使用class,而是使用className(为了避免跟ES6中定义的class产生冲突,所以采用className);
  4. 在写内联样式的时候,要写成style={{color:'red',fontSize:'20px'}}这样,变量加引号,有横杆的变量名用小驼峰写法;
  5. 虚拟DOM必须只有一个根标签(类似于Vue3版本之前那样,template中只能有一个根标签);
  6. 内部标签必须闭合;
  7. jsx中,标签首字母如果是小写开头,则将该标签转化为html中同名元素,如果html中无同名元素(标签),则报错;标签首字母如果是大写开头,React就会去渲染对应的组件,若组件没定义,就报错。

JS语句(代码)以及JS表达式

表达式 语句(代码)
一个表达式会产生一个值,可以放在任何一个需要值的地方 控制代码走向,没有值
a if(){}
a+b for(){}
demo(1) switch(){case:xxxx}
arr.map()
function test() {}
arr.map用法

map的用法

不用使用index作为遍历的key。

组件

用来实现局部功能效果的代码和资源的整合。复用编码,简化项目编码,提高运行效率。

React面向组件编程

函数式组件 ——无State

  1. React解析组件标签,找到了Demo组件;
  2. 发现组件是使用函数定义的,随后调用该函数,将返回的DOM转化为真实DOM,随后呈现在页面中。

ES6中类的基本知识

  1. 类中的构造器不是必须写的,要对实例进行一些初始化的操作,如添加指定属性时才写;
  2. 如果A类继承了B类,且A类中写了构造器,那么A类构造器中super是必须要调用的;
  3. 类中定义的方法,都是放在了类的原型对象上,供实例使用。
class Person {
    constructor(name,age) {
        this.name = name;
        this.age = age;
    }
  
    // 类中可以直接写赋值语句
    // 给类的实例对象添加一个属性,名字为val,值为1
    val = 1
    
    // 类中的一般方法
    speak() {
        // speak方法放在了哪里 ————类的原型对象上,供实例使用
        // 通过Person实例调用speak时,speak中的this就是Person实例
        console.log("我叫${this.name},我年龄是${this.age}");
    }
}

class Student extends Person {
    constructor(name, age, grade) {
        // 必须在最开始调用
        super(name, age);
        this.grade = grade;
    }
    
    // 重写
    speak() {
        console.log("我叫${this.name},我年龄是${this.age},正在读${this.grade}");
    }
    
    // 独有方法
    study() {
        // study方法放在了哪里 ————类的原型对象上,供实例使用
        // 通过Student实例调用study时,study中的this就是Student实例
        console.log("Study");
    }
}

类中方法的this指向

class Person {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
    // 类中所定义的方法,在局部定义了严格模式
    speak() {
        console.log();
    }
}

const p = new Person("Name",1);
p.speak();// 通过实例调用study方法
const x = p.speak;
x();

Call

更改实例中的this指向对象,例如

person.speak.call({a:1,b:2});
// 传过去的值就会是那个对象

类式组件(P11)—— 有State

类名就是组件名

// 必须继承React.Component React内置类
// 必须有render
// 必须有返回值
class ComponentName extends React.Component {
     render() {
         // render放在ComponentName的原型对象上,供实例使用
         // render中的this——组件实例对象 <=> 实例对象
         return (<h1>Hello</h1>)
     }
}
// 渲染组件到页面
ReactDOM.render(<ComponentName/>, document.getElementById('idName'))
// React解析组件标签,找到了组件
// React发现组件是类定义的,随后new出该类的实例,并通过该实例调用到原型上的render方法
// 将render返回的虚拟DOM转化为真实DOM,随后呈现在页面中

人状态影响行为;

组件状态驱动页面展示。

JS几种点击方式

js点击

同样可以用在JSX中,但是在JSX中主要推荐第三种。

展开运算符(...)

const a = [1,3,5,7,9]
const b = [2,4,6,8,10]
console.log(...a); // 展开一个数组: 1 3 5 7 9 
let c = [...a, ...b]// 连接数组

// 在函数中使用
function sum(...numbers) {
    return numbers.reduce((per, cur) => {
        return per + cur
    })
}

let person = {name:"a" ,age:18}
// 复制对象
let person2 = {...person};
console.log(...person)// 报错
// 合并
let p3 = {...person,name:"C"}

Reduce

let arr = [1,2,3,4,5]
// 初级应用 求和求积
console.log(arr.reduce(a,b) => a + b))// 15
console.log(arr.reduce(a,b) => a*b))// 120
// 计算数组中每个元素的出现次数
let arr = ['name','age','long','short','long','name','name'] 

let arrResult = arr.reduce((pre,cur) =>{
    console.log(pre,cur)
    if(cur in pre){
        pre[cur]++
    }else{
        pre[cur] = 1
    }
    return pre
},{})

console.log(arrResult)//结果:{name: 3, age: 1, long: 2, short: 1}

// 数组去重
let arrResult = arr.reduce((pre,cur) =>{
    if(!pre.includes(cur)){
        pre.push(cur)
    }
    return pre;
},[])

console.log(arrResult)//结果:["name", "age", "long", "short"]

// 对象属性求和等
let person = [
    {
        name: 'xiaoming',
        age: 18
    },{
        name: 'xiaohong',
        age: 17
    },{
        name: 'xiaogang',
        age: 19
    }
]

let result = person.reduce((a,b) =>{
    a = a + b.age;
    return a;
},0)

console.log(result)//结果:54

Static

类通过static关键字定义静态方法。不能在类的实例上调用静态方法,而应该通过类本身调用。可以参照static - MDN

class ClassWithStaticMethod {

  static staticProperty = 'someValue';
  static staticMethod() {
    return 'static method has been called.';
  }

}

console.log(ClassWithStaticMethod.staticProperty);
// output: "someValue"
console.log(ClassWithStaticMethod.staticMethod());
// output: "static method has been called."

组件实例的几个主要属性

State(P13、P14)——因为有setState?

class Weather extends React.Component {
    // 构造器只调用了一次
    constructor(props) {
        super(props);
        // React官方要求对象
        // 初始化状态
        this.state = {key1: val1, key2: val2}
        // 右侧第一个this是组件实例对象
        // bind生成一个新的函数,并且改变this的指向
        // 给自身一个functionName
        // 解决functionName this指向问题
        this.functionName = this.functionName.bind(this)
	}
  
    // render调用了 1+n 次
    // 1是初始化那次
    // n是状态更新的次数
    render() {
        // 读取状态
        const {key1, key2} = this.state
        // React基本给js所有on开头的方法都做了重写,换成小驼峰
        return (

Str{key1 ? "true" : "false"}

) } // 不是通过实例调用的 // 点几次调用几次 functionName() { // 作为onClick的回调,所以不是通过实例调用的,是直接调用 // 类中的方法默认开启了局部的严格模式,所以functionName中的this为undefined // 获取原值 const key1 = this.state.key1; // 严重注意:状态不可直接更改,要借助一个内置的API去更改 // 直接更改,错误写法 => this.state.key1 = !key1; // 严重注意:状态必须通过setState进行更新,且更新是合并例如下边这样 // 如果只给一个key1,只会替换key1的,不会影响到其他的。 this.setState({key1: !key1}) } } ReactDOM.render(,document.getElementById('idName'))
// 简写方式
class Weather extends React.Component {
    // 初始化状态
    this.state = {key1: val1, key2: val2}

    render() {
        const {key1, key2} = this.state
        return (

Str{key1 ? "true" : "false"}

) } // 箭头函数没有自己的this,它会找外层this作为自己的this // 自定义方法(赋值语句的形式 + 箭头函数) functionName = () => { const key1 = this.state.key1; this.setState({key1: !key1}) } } ReactDOM.render(,document.getElementById('idName'))

走向

总结

  1. 组件对象最重要的属性,值是对象,包含多个key-value
  2. 组件被称为“状态机”,通过更新组件的state来更新对应的页面显示(重新渲染组件)
  3. 组件中render方法中的this为组件实例对象
  4. 组件自定义的方法中this为undefined是,通过两种形式:
    1. 强制绑定this:通过对象的bind()
    2. 使用箭头函数
  5. 状态数据不能直接修改或者赋值。

P19结束。

props

Props是只读的。

通过标签传值到组件,就类似于Vue中的父子组件传值

class Component extends React.Component {
    // 构造器是否接收props,是否传递给super,取决于是否希望在构造器中通过this范围props
    // 类中构造器能省则省
    remder() {
        return (

11

) } } // 批量传值 // ES6 扩展运算符(展开运算符) // 批量传递标签属性(props) // 对传递的标签进行类型限制 // 设置默认值 // 设置是否必填 // function改为func

函数式组件是用props

function Person(props) {
    const {key1, key2} = props
    return (
        
  • key1
  • key2
) } // 类型、默认值以及是否必填可以写在外边。

refs

相当于原生的ID,标识自己。

发生事件的元素就是要操作的元素,可以省略ref。

Vue中的this.$refs.refName.function();

字符串形式(不被支持)

字符串的ref存在一些效率问题。

class Demo extends React.Component {
    render() {
        return(
        	
提示 // onBlur失去焦点
) } showData = () => { // 解构赋值 const {input1} = this.refs alert(input1.value) } showData2 = () => { // 解构赋值 const {input2} = this.refs alert(input2.value) } }

回调类型

回调函数:

  1. 你定义的函数
  2. 你没调用
  3. 别人调用了
class Demo extends React.Component {
    render() {
        return(
        	
this.input1 = c}/> 提示 // onBlur失去焦点 this.input2 = c} onBlur={this.showData2}/>
) } showData = () => { const {input1} = this alert(input1.value) } showData2 = () => { const {input2} = this alert(input2.value) } }
回调执行次数的问题

如果ref回调函数是以内联函数形式定义的,在更新过程中它会被执行两次,第一次传入参数null,第二次传入才是对应的Node。这是因为在每次渲染的时会创建一个新的实例,所以React清空旧的ref并且设置新的。通过ref的回调函数定义成class的绑定函数可以避免上述问题。

class Demo extends React.Component {
    state = {isHot: true}
  
    showData = () => {
        const {input1} = this
        alert(input1.value)
    }
  
    changeWeather = () => {
        const {isHot} = this.state;
        this.setState({isHot:!isHot})
    }
  
    saveInput = (c) => {
        this.input1 = c;
        console.log("@",c)
    }
  
    render() {
        const {isHot} = this.state
        return(
        	

今天天气{isHot?"re":"len"}

{/* {this.input1 = c;this.console.log("@",c)}/>*/} 提示 更换
) } }

createRef API类型(官方最推荐)

class Demo extends React.Component {
    // React.createRef条用后可以返回一个容器,该容器可以存储被ref所标识的节点,该容器是“专人专用”
    myRef = React.createRef()
  
	showData = () => {
        const {current} = this.myRef
        alert(current.value)
    }

    render() {
        return(
        	
提示
) } }

P31结束

React事件处理

  1. 通过onXxx属性指定事件处理函数(注意大小写)
    1. React使用的是自定义事件,而不是使用的原生DOM事件 ——为了更好的兼容性
    2. React中的事件是通过事件委托方式处理的(委托给组件最外侧的元素) —— 为了高效
  2. 通过event.target得到发生事件的DOM元素对象 ——不要过度使用ref
class Demo extends React.Component {
    // 创建容器
    myRef = React.createRef()
  
	showData = () => {
        alert(this.myRef.current.value)
    }
  
    // event 发生事件的事件对象
    showData2 = (event) => {
        alert(event.target.value);
    }

    render() {
        return(
        	
提示
) } }

收集表单数据

非受控组件

class Login extends React.component{
    handleSubmit = (event) => {
        event.preventDefault()// 阻止(表单提交)默认事件
        const {username, password} = this
    }
  
    // 页面类所有输入类的DOM,现用现取
    render(){
        return(
            
登录 ) } }

受控组件(推荐这种写法)

像是手写了Vue的双向绑定。

class Login extends React.component{
    // 初始化状态
    state = {
        username:"",
        password:""
    }
    // 提交表单
    handleSubmit = (event) => {
        event.preventDefault()// 阻止(表单提交)默认事件
        const {username, password} = this.state
        alert(username,password)
    }
    // 保存用户名
    demo = (event) => {
        console.log(event.target.value)
        this.setState({username:event.target.value})
    }
  
    render(){
        return(
            
登录 ) } }

高阶函数_函数柯里化

saveFromData就是高阶函数,如果符合下边两个规范中的任何一个,那就是高阶函数

  1. 如果A函数接收的参数是一个函数,那么A就可以称为高阶函数。
  2. 如果A函数的返回值是一个函数,那么A就可以称为高阶函数。
  3. 常见的高阶函数:
    1. Promise: new Promise(() => ())
    2. setTimeout:(() => {})
    3. 数组身上的常见函数,例如arr.map

函数的柯里化

通过函数调用继续返回函数的方式,实现多次接收参数最后统一处理的编码形式。

function sum(a,b,c){
    return a+b+c;
}
res = sum(1,2,3)

// 函数柯里化
function sum(a){
    return(b)=>{
        return(c)=>{
            return a+b+c
        }
    }
}
res = sum(1)(2)(3)
// 如下例子

不用柯里化的实现

对象相关的知识

let a = 'name'
let obj = {}
obj[a] = 'tom' // 外加方括号给对象新增属性
console.log(obj)// {name:"tom"}

React生命周期

引出生命周期

  1. 组件挂载到页面(mount)
  2. 组件从界面卸载(unmount)
// 生命周期回调函数 <==> 生命周期钩子函数 <==> 生命周期函数 <==> 生命周期钩子
class Life extends React.Component {
    state = {opacity:1}
    // 卸载一个组件
    death = () => {
        ReactDom.unmountComponentAtNode(document.getElementById('test'))
    }
  
    // 类似于vue中的mounted
    // 组件挂完后调用
    componentDidMount(){
        this.timer = setInterval(() => {
            let {opacity} = this.state
            opacity -= 1
            if(opacity <= 0){
                opacity = 1
            }
            this.setState({opacity})
        },200)
    }

	// 组件将要卸载
	componentWillUnmount(){
        // 清除定时器
        clearInterval(this.timer);
    }
  
    render() {
        // 如果写在这里,修改state触发render,无限调用了
        /* setInterval(() => {
            let {opacity} = this.state
            opacity -= 1
            if(opacity <= 0){
                opacity = 1
            }
            this.setState({opacity})
        },200)*/
        return (
        

String

隐去
) } }
  1. 组件从创建到死亡会经历一些特定的阶段;
  2. React组件中包含一些利钩子函数,会在特定时刻调用;
  3. 我们在定义组件时,会在特定的生命周期回调函数中,做特定的工作

生命周期(旧)

class Count extends React.Component{
    // 构造器
    constructor(props){
        super(props)
        console.log("Count-constructor")
        this.state = {count:0}
    }
    death = () => {
        ReactDOM.unmountComponentAtNode(document.getElementById('test'))
    }
	add = () => {
        const {count} = this.state
        this.setState = {{count:count + 1}}
    }
    update = () => {
        this.forceUpdate()
    }
    // 组件将要挂载的钩子
    componentWillMount() {
        console.log("Count-componentWillMount")
    }
	// 组件将挂载完毕的钩子
    componentDidMount() {
        console.log("Count-componentDidMount")
    }
	// 卸载组件
	componentWillUnmount(){
        console.log("Count-componentWillUnmount")
    }
	componentWillReceiveProps(){
  
    }
	// 组件是否应该被更新
	// 类似阀门一样的东西,是否允许更新
	// 不写,默认返回true
	// 如果写了函数,不给返回值,会报错,一定要有返回值
	shouldComponentUpdate(){
        console.log("Count - shouldComponentUpdate");
        return true / false;
    }
	// 组件将要更新
	componentWillUpdate(){
        console.log("Count - componentWillUpdate");
    }
	// 组件更新完毕
	componentDidUpdate(){
        console.log("Count - componentDidUpdate");
    }
    render(){
        console.log("render")
        const {count} = this.state
        return(
        	

求和:{count}

加 卸载组件 不更改数据更新
) } } class A extends React.Component{ state = {carName:"奔驰"} changeCar = () => { this.setState({carName:"奥拓"}) } render(){ return(
A
) } } class B extends React.Component{ componentWillReceiveProps(){ console.log("B——componentWillReceiveProps") } render(){ return(
B,:{this.props.carName}
) } }
  1. 初始化阶段:由ReactDOM.render()触发——初次渲染1. constructor() 2. componentWillMount() 3. render() 4. componentDidMount() ——常用,一般在这个钩子中做一些初始化的事儿,例如开启定时器或者发送网络请求、订阅消息
  2. 更新阶段:由组件内部this.setState()或父组件render触发1. shouldComponentUpdate() 2. componentWillUpdate() 3. render()——必须用 4. componentDidUpdate()
  3. 卸载组件:由ReactDOM.unmountComponentAtNode()触发1. componentWillUnmount()——一般在这个钩子中做一些收尾的事儿,例如:关闭定时器、取消订阅消息。

生命周期(新)

到P48

DOM的Diffing算法

虚拟DOM对比的最小力度是标签。如果标签里套标签,也还会逐层比较。

一道面试题

  1. React / Vue中的key有什么作用?(key的内部原理是啥)

  2. 为什么遍历列表时,key最好不要用index。

  3. 虚拟DOM中key的作用

    1. 简单的说:key是虚拟DOM对象的标识,在更新显示时key起着极其重要的作用。
    2. 详细的说:当状态中的数据发生变化时,react会根据新数据生成新的虚拟DOM,随后React进行新虚拟DOM与旧虚拟DOM的diff比较,比较规则如下:1. 旧虚拟DOM中找到了与新虚拟DOM相同的ky:1. 若虚拟DOM中内容没变,直接使用之前的真实DOM 2. 若虚拟DOM中内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM 3. 旧虚拟DOM中未找到与新虚拟DOM相同的key,根据数据创建新的真实DOM,随后渲染到页面。
  4. 用index作为key可能会引发的问题:

    1. 若对数据进行:逆序添加、逆序删除等破坏顺序操作:会产生没有必要的真实DOM更新=>界面效果没问题,但是效率低
    2. 如果结构种还包含输入类的DOM:会产生错误DOM更新 => 界面有问题
    3. 如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,使用index作为key是没有问题的。
  5. 如何选择key:

    1. 最好使用每条数据的唯一表示作为key,例如ID、手机号、身份证等唯一值;
    2. 如果只用展示,不做操作,可以使用index作为key。

React脚手架

  1. React提供了一个用于创建react项目的脚手架库:create-react-app。
  2. 项目整体技术架构为:React + webpack + es6 + eslint
  3. 使用脚手架开发的项目的特点:模块化、组件化、工程化。

单页面应用

SPA应用 single page application

文件说明

  1. public:一般存储静态资源

    1. favicon.ico:网站的title图标
    2. index.html:public下有且仅有一个html文件
    3. manifest:类似Android的那个manifest文件
    4. robots:配置爬虫规则文件
  2. src:

    1. App.js:创建了一个名为APP的组件
    2. App.css:App组件的样式
    3. index.js:入口文件

    P52

SPA应用

  1. 单页web应用
  2. 整个应用只有一个完整的页面
  3. 点击页面中的链接不会刷新页面,只会做页面的局部更新
  4. 数据都需要通过ajax异步获取,并在前端展现
  5. 单页面多组件

路由

一个路由就是一个映射关系,key为value,value可能是function或component。

HashRouter会出现#,Brower不会出现。

明确导航区、展示区。

路由组件与一般组件

  1. 写法不同:1. 一般组件:<Demo/> 2. 路由组件:<Route path='/demo' component={Demo}/>
  2. 存放位置不同:1. 一般组件:component 2. 路由组件:pages
  3. 接收到的props不同:1. 一般组件:写标签时传递了什么,就能接收到什么 2. 路由组件:{history:{},location:{},match:{}}

NavLink与封装MyNavLink

  1. NavLink可以实现路由链接的高亮,通过activeClassName指定样式名
  2. 标签体内容是一个特殊的标签属性
  3. 通过this.props.children可以获取标签体内容

如果router path有重复

```都会展示出来

### 精准匹配与模糊匹配

两种情况:

1. navLink那边给多了,也就是到了子路径,route可以检测,例如navLink到`/home/a/b`,route的path为:`/hone`这样可以匹配
2. 反之则不行。

![](https://img.imgdb.cn/item/604b11a35aedab222ca8bf1f.jpg)

React用params多点

```# Redux类似Vue中的Vuex

1. Redux是一个专门用于做状态管理的JS库不限于React使用
2. 可以用在ReactAngularVue等项目中但基本与React配合使用
3. 作用集中式管理React应用多个组件共享的状态

## 什么时候使用Redux

1. 某个组件的状态需要让其他组件可以随时拿到
2. 一个组件需要改变另一个组件的状态
3. 总体原则能不用就不用如果不用的时候编码比较吃力才考虑使用

![](https://img.imgdb.cn/item/604c41735aedab222c2ab260.jpg)

纯函数

  1. 一类特别的函数:只要是同样的输入,必定有同样的输出
  2. 必须遵守以下的约束:
    1. 不得改写任何参数数据
    2. 不会产生任何副作用,例如网络请求、输入输出等
    3. 不能调用Date.now()或者Math.random()等不纯的方法
  3. redux中的reducer函数必须是一个纯函数。

空文件

简介

个人学习React仓库 展开 收起
HTML/CSS
取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
HTML/CSS
1
https://gitee.com/a-little-cool/react_site.git
git@gitee.com:a-little-cool/react_site.git
a-little-cool
react_site
react_site
master

搜索帮助