React基础核心

React简介

什么是react?

react是一个构建用户可视化组件的JavaScript库,通虚拟DOM有效的控制真实DOM,遵循数据从高阶组件流向低阶组件的单向数据流。

为什么要学习react?

1、原生JavaScript操作DOM繁琐、效率低(DOM-API操作UI)

2、使用JavaScript直接操作DOM,浏览器会进行大量的重绘、重排。

3、原生JavaScript没有组件化编码方案,代码复用率低。

react的特点?

1、采用组件化模式、申明式编码,提高开发效率及组件复用率。

2、在react native中可以使用react语法进行移动端开发。

3、使用虚拟DOM和优秀diffing算法,尽量减少与真实DOM的交互。

JSX语法

JSX 是 javascript 的语法扩展。它就像一个拥有 javascript 全部功能的模板语言。它生成 React 元素,这些元素将在 DOM 中呈现。React 建议在组件使用 JSX。在 JSX 中,我们结合了 javascript 和 HTML,并生成了可以在 DOM 中呈现的 react 元素。

  1. 定义虚拟 dom 时不要用引号
  2. 标签中引入 js 表达式要用 {}
  3. 如果在 jsx 要写行内样式需要使用 style={{coler:red}} 形式
  4. 样式的类名指定不能写 class,要写 className;
  5. 只有一个根标签
  6. 标签必须闭合
  7. 标签首字母

         ①若小写字母开头,则会将该标签转为 html 同名标签,如果没找到,则会报错;

        ②若大写字母开头,则会认为是组件,它就会去找对应的组件,如果没找到,就会报组件未定义的错误;

实质:JSX 通过 babel 编译,而 babel 实际上把 JSX 编译给 React.createElement() 调用
 

React的基本使用

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <meta http-equiv="X-UA-Compatible" content="IE=edge">

    <meta name="viewport" content="width=device-width, initial-scale=1.0">

  <title>Document</title>
</head>



<body>

  **

    <div id="test">123</div>
<script type="text/javascript" src="../js/react.development.js" ></script>
**

<script type="text/javascript" src="../js/react-dom.development.js"></script>
**

<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/babel">  //此处一定要写babel

*//1、创建虚拟DOM*

const VDOM=<h1>hello,react</h1> *//此处一定不要写引号,因为不是字符串*

*//2、渲染虚拟DOM到页面上*

ReactDOM.render(VDOM,document.getElementById('test'))





</body>

</html>

虚拟DOM的两种创建方式

1、使用jsx创建虚拟DOM

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <meta http-equiv="X-UA-Compatible" content="IE=edge">

    <meta name="viewport" content="width=device-width, initial-scale=1.0">

  <title>Document</title>
</head>



<body>

  **

    <div id="test"></div>
<script type="text/javascript" src="../js/react.development.js" ></script>
**

<script type="text/javascript" src="../js/react-dom.development.js"></script>
**

<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/babel">  //此处一定要写babel

*//1、创建虚拟DOM*

const VDOM=(<h1 id='title'>

​        <span>hello,react</span>

​      </h1> )*//此处一定不要写引号,因为不是字符串*

*//2、渲染虚拟DOM到页面上*

ReactDOM.render(VDOM,document.getElementById('test'))





</body>

</html>

2、使用js创建虚拟DOM

​​

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <meta http-equiv="X-UA-Compatible" content="IE=edge">

    <meta name="viewport" content="width=device-width, initial-scale=1.0">

  <title>Document</title>
</head>



<body>

  **

    <div id="test"></div>
<script type="text/javascript" src="../js/react.development.js" ></script>
**

<script type="text/javascript" src="../js/react-dom.development.js"></script>
<script type="text/javascript"> 

*//1、创建虚拟DOM*

const VDOM=React.creatElement('h1',{id:"title"},React.creatElement('span',{},'hello,React'))

*//2、渲染虚拟DOM到页面上*

ReactDOM.render(VDOM,document.getElementById('test'))





</body>

</html>

3、虚拟DOM与真实DOM的区别

​​

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <meta http-equiv="X-UA-Compatible" content="IE=edge">

    <meta name="viewport" content="width=device-width, initial-scale=1.0">

  <title>虚拟DOM与真实DOM</title>
</head>



<body>

  **

    <div id="test"></div>
    <div id="demo"></div>
<script type="text/javascript" src="../js/react.development.js" ></script>
**

<script type="text/javascript" src="../js/react-dom.development.js"></script>
**

<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/babel">  //此处一定要写babel

*//1、创建虚拟DOM*

const VDOM=(<h1 id='title'>

​        <span>hello,react</span>

​      </h1> )*//此处一定不要写引号,因为不是字符串*

*//2、渲染虚拟DOM到页面上*

ReactDOM.render(VDOM,document.getElementById('test'))



console.log("虚拟DOM",VDOM);

const TDOM=document.getElementById('demo')

console.log("真实DOM",TDOM)

*// 关于虚拟DOM:*

*// 1、本质上object类型的对象*

*//2、虚拟DOM比较属性较少,真实DOM属性多,欣因为虚拟DOM是react内部在使用,无需真实DOM那么多属性*

*//3、虚拟DOM最终会被React转换为真实DOM,呈现在页面上。*

</script>

</body>

</html>

模块与组件、模块化与组件化的理解

模块

1)理解:向外提供特定功能的js程序,一般就是一个js文件

2)为什么要拆成模块:随着业务逻辑增加,代码越来越多且复杂

3)作用:复用js,简化js的编写,提高js运行效率

组件

1)理解:用来实现局部功能效果的代码和资源的集合(img、css、html)

2)作用:复用代码,简化项目编码,提高运行效率

模块化

当应用的js都以模块来编写,这个应用就是一个模块化的应用

组件化

当应用是以多组件的方式实现,这个应用就是一个组件化的应用

函数式组件

​​

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <meta http-equiv="X-UA-Compatible" content="IE=edge">

    <meta name="viewport" content="width=device-width, initial-scale=1.0">

  <title>函数式组件</title>
</head>



<body>

  **

    <div id="test"></div>
<script type="text/javascript" src="../js/react.development.js" ></script>
**

<script type="text/javascript" src="../js/react-dom.development.js"></script>
**

<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/babel">  //此处一定要写babel

*//1、创建函数式组件*

function MyComponent(){

  console.log(*this*)*//此处的this是undefined,因为babel开启了严格模式*

  return (<h2>我是用函数定义的组件(适用于【简单组件】的定义)</h2>)

}

*//2、渲染组件到页面*

ReactDOM.render(<MyComponent/>,document.getElementById('test'))

*/**

 *执行了ReactDOM.render(,document.getElementById('test'))之后发生了什么*

*1、React解析组件标签,找到组件标签*

*2、发现组件时使用函数定义的,随后调用该函数,将返回的虚拟DOM转换为真实DOM,随后呈现在页面中*

**/*



</script>

</body>

</html> 

类式组件

//1、创建类式组件*

  class MyComponent extends React.Component{

​    render(){

​      *//render是放在哪里的?--类的原型对象上,给实例使用*

​      *//render中的this是谁?--类的原型对象*

​      return (<h2>我是用类定义的组件(适用于【复杂组件】的定义)</h2>)

​    }

  }

  *// 2、渲染组件到页面*

  ReactDOM.render(<MyComponent/>,document.getElementById('test'))

  */**

 *执行了ReactDOM.render(,document.getElementById('test'))之后发生了什么*

*1、React解析组件标签,找到组件标签*

*2、发现组件是使用类定义的,随后new出该类的实例,并通过该实例调用到原型上的render方法*

*3、将render返回的虚拟DOM转换为真实DOM,随后呈现在页面中*

组件实例三大属性1——state

理解

1)state是组件对象最重要的属性,值是对象(可以包含多个key-value的组合)

2)组件被称为“状态机”,通过更新组件的state来更新对应的页面显示(重新渲染组件)

状态数据不能直接赋值,需要用 setState()

setState()有同步有异步,基本上都是异步更新,自己定义的DOM事件里setState()是同步的

1)state是组件对象最重要的属性,值是对象(可以包含多个key-value的组合)

2)组件被称为“状态机”,通过更新组件的state来更新对应的页面显示(重新渲染组件) 

*//1、创建组件*

  class Weather extends React.Component{    

​    *// 初始化状态*  

​    state= {

​       isHote:true,

​       wind:'微风'

​      }



​    render(){

​      const {isHot,wind}=*this*.state

​      return <h1 onClick={this.changeWeather}>今天天气很{isHot ? '炎热':'凉爽'},{wind}</h1>

​    }

  *//  自定义方法---要用赋值语句+箭头函数*

​    changeWeather=()=>{

​    const isHot=*this*.state.isHot

​    *this*.setState({isHot:!isHot})

  }



  

  }

*//   2渲染到也页面*

  ReactDOM.render(<Weather/>,document.getElementById('test'))

强烈注意

1)组件中render方法中的this为组件实例对象

2)组件自定义的方法中this为undefined,如何解决?

a。强制绑定this:通过 函数对象的bind()

b。箭头函数

3)状态数据,不能直接修改或者更新,需要通过this.setState({})

组件实例三大属性2——props(只读)

理解

1)每个组件对象都会有props属性

2)组件标签的所有属性都保存在props中

作用

1)通过标签属性从组件外部向组件内部传递变化的数据

2)注意:组件内部不要修改props数据

// 1、创建组件*

class Person extends React.Component{

*// 对标签属性进行类型、必要性的限制*

static propTypes={

  name:PropTypes.string.isRequired,*//限制name必传,且为字符串*

  gender:PropTypes.string,*//限制gender为字符串*

  age:PropTypes.number,*//限制age为数值*

  speak:PropTypes.func,*//限制speak为函数*

}

*// 指定标签的默认值*

static defaultProps={

  gender:'男',*//gender默认值为男*

  age:15*//age默认值为15*

}

  render(){

​    const {name,age,gender}=*this*.props

​    *// this.props.name='jacak'//此行代码会报错,因为props是只读的*

return (

  <ul>

​    <li>姓名:{name}</li>

​    <li>年龄:{age+1}</li>

​    <li>性别:{gender}</li>

  </ul> 

​     )

  }

}



const p1={name:'张三',age:12,}

const p2={name:'Lisa',gender:'女'}

*// 渲染组件*

ReactDOM.render(<Person {...p1} speak= {speak}/>,document.getElementById('test1'))

ReactDOM.render(<Person {...p2}/>,document.getElementById('test2'))



 function speak(){

  console.log('我说话了')

}

编码操作

1)内部读取某个属性值

this.props.name

2)对props中的属性值进行类型限制和必要性限制

使用prop-types库进行限制(需要引入prop-types库)

Person.propTypes = {

name:PropTypes.string.isRequired,

age:PropTypes.number

}

3)扩展属性:将对象的所有属性通过props传递

<Person {...person}/>

4)默认值设置

Person.defaultProps={

age:18,

sex:'男'

}

5)组件类的构造函数

constructor(props){

super(props)

console.log(props)//打印所有属性

}

组件实例三大属性3——refs

refs 是组件实例对象中的属性,它专门用来收集那些打了 ref 标签的 dom 元素

比方说,组件中的 input 添加了一个 ref=“input1”

那么组件实例中的 refs 就 ={input1:input(真实 dom)}

这样就可以通过 this.refs.input1 拿到 input 标签 dom 了

就不需要想原生 js 那样通过添加属性 id,

然后通过 document.getElementById (“id”) 的方式拿
 

字符串形式ref(最快速,但官网不推荐了)

//1、创建组件

class Demo extends React.Component{

showDate=()=> {

console.log(this.refs)

}

showDate2=()=> {

const{input2}=this.refs

console.log(input2.value)

}

render(){

return (<div>

<input type="text" ref='input1' palceholder='点击按钮提示数据'/> 

点击提示左侧数据 

<input type="text" ref='input2' onBlur={*this*.showDate} palceholder='失去焦点提示数据'/>

</div>)

}

}

//2、渲染组件到页面

ReactDOM.render(<Demo/>,document.getElementById('test'))

回调函数形式的ref

*//1、创建组件*

class Demo extends React.Component{

 showDate=()=>{

   console.log(*this*.input1.value)

 }

 showDate2=()=>{

   console.log(*this*.input2.value)

 }

  render(){

​    return (

            <div>

​      <input type="text" ref={(currentNode)=>{*this*.input1=currentNode}}  palceholder='点击按钮提示数据'/>&nbsp;

​      <button  onClick={*this*.showDate}>点击提示左侧数据</button>&nbsp;

​      <input type="text" ref={(currentNode)=>{*this*.input2=currentNode}}  onBlur={*this*.showDate2} palceholder='失去焦点提示数据'/>

​      

​      </div>

​      )

  }

  

}

  *//2、渲染组件到页面*

  ReactDOM.render(<Demo/>,document.getElementById('test'))

createRef创建ref容器

 *//1、创建组件*

class Demo extends React.Component{

  *// React.createRef调用后可以返回一个容器,该容器可以存储被ref所标识的节点,该容器是“专人专用”的*

  myRef = React.createRef()

  myRef2 = React.createRef()

 showDate=()=>{

   alert(*this*.myRef.current.value)

 }

 showDate2=()=>{

   alert(*this*.myRef2.current.value)

 }

  render(){

​    return (

            <div>

​      <input type="text" ref={*this*.myRef}  palceholder='点击按钮提示数据'/>&nbsp;

​      <button  onClick={*this*.showDate}>点击提示左侧数据</button>&nbsp;  

​      <input type="text" onBlur={*this*.showDate2} ref={*this*.myRef2}  palceholder='失去焦点提示数据'/>&nbsp;     

​      </div>

​      )

  }

  }

  *//2、渲染组件到页面*

  ReactDOM.render(<Demo/>,document.getElementById('test'))

事件处理

(1)通过onXxx属性指定事件处理函数(注意大小写)

a.React使用的是自定义(合成)事件,而不是使用的原生DOM事件————为了更好的兼容性

b.React中的事件是通过事件委托方式处理的(委托费组件最外层的元素)---为了高效

(2) 通过event.target得到发生事件的DOM元素对象----不要过度使用ref

【注意】发生事件对象和操作对象是同一个时候,可以省略ref,通过event调用事件


 *//1、创建组件*

  class Demo extends React.Component{

  *// 创建ref容器*

​    myRef = React.createRef()

​    myRef2 = React.createRef()





 showDate=()=>{

   alert(*this*.myRef.current.value)

 }





 showDate2=(e)=>{

   alert(e.target.value)

 }

  render(){

​    return (

            <div>

​      <input type="text" ref={*this*.myRef}  palceholder='点击按钮提示数据'/>&nbsp;

​      <button  onClick={*this*.showDate}>点击提示左侧数据</button>&nbsp;  

​      <input type="text" onBlur={*this*.showDate2}  palceholder='失去焦点提示数据'/>&nbsp;     

​      </div>

​      )

  }

  

}

  *//2、渲染组件到页面*

  ReactDOM.render(<Demo/>,document.getElementById('test'))

收集表单数据

理解

包含表单的组件分类

a.受控组件(建议使用)

class Login extends React.Component{

​        

​        *// 初始化状态*

​        state={username:'',password:''}



​        *// 表单提交回调*

​        showInfo=(event)=>{

​          event.preventDefault()*//阻止表单提交*

​          const {username,password}=*this*.state

​          alert('用户名:'+username+'密码:'+password)

​        }



​        *// 保存用户名信息*

​        saveUsername=(e)=>{

​          *this*.setState({username:e.target.value})

​        }



​        *// 保存密码信息*

​        savePassword=(e)=>{

​          *this*.setState({password:e.target.value})

​        }



​        render(){

​          return(

​            <form action="http://www.baidu.com" onSubmit={*this*.showInfo}>

​            <span>用户名:</span>   

​            <input type="text" onChange={*this*.saveUsername}  name="username"/>

​            <span>密码:</span>

​            <input type="password"  onChange={*this*.savePassword} name="password"/>

​            <button >登录</button>

​            </form>

​          )

​        }

​      }



​      *//渲染页面*  

​      ReactDOM.render(<Login/>,document.getElementById('test'))

b.非受控组件

class Login extends React.Component{

​        showInfo=(event)=>{

​          event.preventDefault()*//阻止表单提交*

​          const {username,password}=*this*

​          alert('用户名:'+username.value+'密码:'+password.value)

​        }



​        render(){

​          return(

​            <form action="http://www.baidu.com" onSubmit={*this*.showInfo}>

​            <span>用户名:</span>   

​            <input type="text" ref={currentNode=>*this*.username=currentNode} name="username"/>

​            <span>密码:</span>

​            <input type="password" ref={currentNode=>*this*.password=currentNode} name="password"/>

​            <button >登录</button>

​            </form>

​          )

​        }

​      }

ReactDOM.render(<Login/>,document.getElementById('test'))

高阶函数柯里化

使用高阶函数柯里化实现

 <script type="text/babel">  //此处一定要写babel
            /*
            高阶函数:如果一个函数符合下面2个规范中的任何一个,那么该函数就是高阶函数
                    1、若A函数,接受的参数是一个函数,那个A就可以称为高阶函数
                    2、若A函数,调用的返回值依然是一个函数,那么A就可以称为高阶函数。
                    常见的高阶函数有:Promise、setTimeout、arr.foreach()等等

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

            class Login extends React.Component{
                
                // 初始化状态
                state={username:'',password:''}


                // 表单提交回调
                showInfo=(event)=>{
                    event.preventDefault()//阻止表单提交
                    const {username,password}=this.state
                    alert('用户名:'+username+'密码:'+password)
                }

                saveInfo=(dataType)=>{
                    
                    return (event)=>{
                        this.setState({[dataType]:event.target.value})
                    }
                }


                render(){
                    return(
                        <form action="http://www.baidu.com" onSubmit={this.showInfo} >
                        <span>用户名:</span>    
                        <input type="text" onChange={this.saveInfo('username')}  name="username"/>
                        <span>密码:</span>
                        <input type="password"  onChange={this.saveInfo('password')} name="password"/>
                        <button >登录</button>
                        </form>
                    )
                }
            }

            //渲染页面  
            ReactDOM.render(<Login/>,document.getElementById('test'))
            </script>

不使用高阶函数柯里化实现

<script type="text/babel">  //此处一定要写babel

            class Login extends React.Component{
                
                // 初始化状态
                state={username:'',password:''}


                // 表单提交回调
                showInfo=(event)=>{
                    event.preventDefault()//阻止表单提交
                    const {username,password}=this.state
                    alert('用户名:'+username+'密码:'+password)
                }

                // 保存表单数据到状态中
                saveInfo=(dataType,event)=>{                   
                    this.setState({[dataType]:event.target.value})
                    
                }


                render(){
                    return(
                        <form action="http://www.baidu.com" onSubmit={this.showInfo} >
                        <span>用户名:</span>    
                        <input type="text" onChange={(event)=>{this.saveInfo('username',event)}}  name="username"/>
                        <span>密码:</span>
                        <input type="password"  onChange={(event)=>{this.saveInfo('password',event)}} name="password"/>
                        <button >登录</button>
                        </form>

                    )
                }
            }

            //渲染页面  
            ReactDOM.render(<Login/>,document.getElementById('test'))
            </script>

组件生命周期

理解

1、组件从创建到死亡他会经历一些特定的阶段

2、React组件中包含一系列钩子函数,会在特定的时刻调用

3、我们在定义组件时,会在特定的生命周期回调函数中做特定的工作。

生命周期(旧版本)

生命周期分为三个阶段:

1、初始化阶段:由ReactDOM.render()触发---初次渲染

1、constructor()

2、componentWillMount()

3、render()

4、componentDidMount()======>常用,

一般在这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息

2、更新阶段:由组件内部this.setState()或父组件重新render触发

1、shouldComponentUpdate()

2、componentWillUpdate()

3、render()======>必须使用一个render

4、componentDidUpdate()

3、卸载组件:由ReactDOM.unmountComponentAtNode()触发

1、componentWillUnmount()======>常用

一般在这个钩子中做一些收尾的事,例如:关闭定时器、取消请阅、

生命周期(新)

重要的钩子

1、render:初始化渲染或更新渲染调用

2、componentDidMount:开启监听,发送ajax请求

3、componentWillUnmount:做一些收尾工作,如:清理定时器

虚拟DOM


本质上其实就是一个 object 对象;
虚拟 dom 上的属性比较少,真实 dom 属性多,因为虚拟 dom 只在 react 内部使用,用不到那么多的属性
虚拟 dom 最终会被 react 转换成真实 dom,呈现再页面上
大致过程:

state数据

jsx模版

数据+模版 结合,生成虚拟DOM

(虚拟DOM就是一个JS对象,用它来描述真实的DOM)(损耗了性能)

用虚拟DOM的结构生成真实的DOM来显示

state发生改变

数据+模版 生成新的虚拟DOM(极大提升了性能)

比较原始虚拟DOM和新的虚拟DOM的区别,找差异(极大提升了性能)

直接操作DOM,改变内容

优点:

性能提升

使得跨端应用得以实现

虚拟 DOM 中的 key 的作用:

当状态中的数据发生改变时,react 会根据新数据生成新虚拟 DOM

随后 react 会进行新虚拟 DOM和旧虚拟 DOM的 diff 算法比较

若旧 DOM中找到了与新 DOM相同的 key,则会进一步判断两者的内容是否相同

如果也一样,则直接使用之前的真实 DOM,如果内容不一样,则会生成新的真实 DOM,替换掉原先的真实 DOM

若旧 DOM中没找到与新 DOM相同的 key,则直接生成新的真实 DOM,然后渲染到页面

不用 index 作为 key 的原因:

若对数据进行逆序添加、逆序删除等破坏顺序的操作时会产生不必要的真实 DOM 更新,造成效率低下

如果结构中还包含输入类的 dom,会产生错误 dom 更新,出现界面异常

diff算法

在 react 中如果某个组件的状态发生改变,react 会把此组件以及此组件的所有后代组件重新渲染

不过重新渲染并不代表会全部丢弃上一次的渲染结果,react 还是会通过 diff 去比较两次的虚拟 dom 最后 patch 到真实的 dom 上

diff 算法只比较同一层级,不跨级比较

tag 不相同则直接删掉重建,不再深度比较;tag 和 key 两者都相同,则认为是相同节点,也不再深度比较

虽然如此,如果组件树过大,diff 其实还是会有一部分的开销

因此react 内部通过 fiber 优化 diff 算法,外部建议开发者使用 SCU 和pureComponent
 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

我要当前端工程师

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

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

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

打赏作者

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

抵扣说明:

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

余额充值