react笔记

react:构建用户界面的javascript库

下载:npm i react react-dom

react 核心,提供创建元素,组件的功能

react-dom 提供DOM相关的功能

基本使用--引入js文件的使用方法

<script>
      const title = React.createElement('h1', null,'hello react')// 标签名  属性  子节点
      ReactDOM.render(title, document.getElementById('root'))  // 标签变量  挂载标签
</script>

 react脚手架

创建react脚手架:npm create-react-app my-app

启动项目:npm start

jsx---javascript xml

简单使用

const title = <h1>hello react!!!</h1>
ReactDOM.render(title, document.getElementById('root'))  // 标签变量  挂载标签

react与html的不同

class-->className   for-->htmlFor   tabindex-->tabIndex

嵌入js表达式

const name = 'mike'
const test = <h1>i am h1</h1>
const title = (<h1>{name}</h1>)
//{}中可以用任意js表达式

条件渲染

const isLoading = true
const loadData = ()=>{
    if(isLoading){
        return <div>loading....</div>
    }
    return <div>加载完毕</div>
}

const title =(
    <h1>{loadData()}</h1>
)

ReactDOM.render(title,document.getElementById('root'))

列表渲染

const songs =[
    {id:1,name:'痴心绝对'},
    {id:2,name:'像我这样的人'},
    {id:3,name:'南山南'}
]

const list ={
    <ul>{songs.map(item=><li key={item.id}>{item.name}</li>)    }</ul>
}

样式处理

// 行内样式
const title =(
    <h1 style={{color:'red',background-color:'skyblue'}}></h1>
)
// 类名添加
const title =(
    <h1 className="name"></h1>
)

react组件基础

函数创建组件--函数组件---大写字母开头---必须有返回值

function Hello(){
    return <h1>hello react!!!</h1>
}
ReactDOM.render(<Hello></Hello>,document.getElementById('root'))

类组件---空return null

class Hello extends React.Component{
    render(){
        return <h1>hello react!!!</h1>
    }
}
ReactDOM.render(<Hello></Hello>,root)

抽离js文件

//hello.js
import react from 'react'
class Hello extends React.Component{
    render(){
        return <h1>hello react!!!</h1>
    }
}
export default Hello

// index.js
import Hello from ''
ReactDOM.render(<Hello></Hello>,root)

react事件处理

 事件绑定

import react from 'react'
class Hello extends React.Component{
    handleClick(){
        console.log(1)
    }
    render(){
        return <h1 onClick={this.handleClick}>hello react!!!</h1>
    }
}
export default Hello

事件对象

import react from 'react'
class Hello extends React.Component{
    handleClick(e){  // e事件对象
        e.preventDefault()
        console.log(1)
    }
    render(){
        return <h1 onClick={this.handleClick}>hello react!!!</h1>
    }
}
export default Hello

有状态组件--类组件和无状态组件---函数组件

有状态和无状态是区分组件页面是否与用户产生交互

组件中的state和setstate

import react from 'react'
class Hello extends React.Component{
    // 第一种写法
    constructor(){
        super(){
            this.state ={
                count:0
            }
        }
    }
    // 第二种写法
    state ={
        count:0
    }
    render(){
        return <h1>{this.state.count}</h1>
    }
}
export default Hello

//获取状态  this.state.count
//修改状态  this.setstate({count:this.state.count+1})

解决this指向问题

onIncrement(){
    console.log(1)
    this.setState({
        count:this.state.count+1
    })
}
//1
<button onClick={()=>this.onIncrement()}></button>
//2
onIncrement=()=>{
    console.log(1)
    this.setState({
        count:this.state.count+1
    })
}
//3
constructor(){
    super()
    this.onIncrement = this.onIncrement.bind(this)
}

表单处理--受控组件和非受控组件

受控组件

import react from 'react'
class Hello extends React.Component{
    state={
        text:''
    }
    render(){
        return <input value={this.state.text} onChange={e=>this.setState({text:e.target.value})}>hello react!!!</input>
    }
}
export default Hello


controlSlect = e =>{
    this.setState({city:e.target.value})
}
<select value={this.state.city} onChange={this.controlSelect}></select>

//复选框
<input type="checkbox" checked={this.state.falg} onChange={e=>{this.setState({falg:e.target.checked})}}></input>

受控组件的优化

1.给表单元素添加name属性,名称与state相同

import react from 'react'
class Hello extends React.Component{
    state={
        text:''
    }
    controlFrom = e =>{
        // 获得当前dom值
        const value = e.terget.type === 'checkbox'? e.target.checked:e.target.value
        const name = e.target.name
        this.setState({
            [name]:value
        })
    }
    render(){
        return <input name="text" value={this.state.text} onChange={this.controlForm})}>hello react!!!</input>
    }
}
export default Hello

非受控组件

import react from 'react'
class Hello extends React.Component{
    constructor(){
        super()
        // 创建ref对象
        this.textRef = React.createRef()
    }
    render(){
        return (
                // 绑定ref
                <input type="text" ref={this.textRef} />
                // 使用ref表单元素值
                <button onClick={e=>{console.log(this.textRef.current.vaule)}}></button>
        )                        
    }
}
export default Hello

组件进阶---数据通信 

<Hello age={19} fn={()=>{console.log(1)}} tag={<p>标签</p>} />

function Hello (props){
    console.log(props.age)
    return null
}

class Hello extends React.Component{
    constructor(props){
        super(props)
    }
    render(){
        return <h1>{this.props.age}</h1>
    }
}

// props是只读对象  只可以读取,不可以修改
// constructor 构造函数是不能直接拿到props

组件通信

父向子

class Parent extends React.Component{
    state={
        lastName='王'
    }
    render(){
        return <Child name={this.state.lastName}></Child>
    }
}

class Child extends React.Component{
    render(){
        return <h1>{this.props.name}</h1>
    }
}

子向父

class Parent extends React.Component{
    state={
        msg:''
    }
    // 1 父组件提供回调函数
    getChildMsg = (data)=>{
        console.log(data)
        // 4改变state
        this.setState({
            msg:data
        })
    }
    render(){
           // 2 子组件通过props调用回调函数
        return <Child fn={this.state.lastName}></Child>
    }
}

class Child extends React.Component{
    state ={
        msg:'hello my father!!'
    }
    render(){
        // 3 子组件调用
        return <button onClick={this.props.fn()}></button>
    }
}

兄弟组件

class Parent extends React.Component{
    state={
        count:0
    }
    controlCount = ()=>{
        this.setState({
            count:this.state.count+1
        })
    }
    render(){
        return (
            <Child1 count={this.state.count}  />
            <Child2 controlCount={this.controlCount} />
        )
    }
}

class Child1 extends React.Component{
    render(){
        return <h1>{this.props.count}</h1>
    }
}

class Child2 extends React.Component{
    render(){
        return <button onClick={this.props.controlCount}>+1</button>
    }
}

context组件----跨组件传递数据

const {Provider,Consumer} = React.createContext()
class Parent extends React.Component{
    
    render(){
        return (
            <Provider value="pink">
                <Child1 />
            </Provider>
        )
    }
}

class Child1 extends React.Component{
    render(){
        return <Child2 />
    }
}

class Child2 extends React.Component{
    render(){
        return (
            <Consumer>
                {data=><p>{data}</p>}
            <Consumer>
        )
    }
}

props深入

children属性:表示组件标签的子节点。当组件标签有子节点时,自动产生

function Hello(props){
    return (
        <div>{props.children}</div>
    )
}


<Hello>这是子节点|<p></p>|{()=>{}}</Hello>

props校验

安装包  npm i prop-types

import PropTypes from 'prop-types'
function App(props){
    return null
}
App.propTypes ={
    colors:PropTypes.array
}

// 约束规则  array bool func number object string element 元素
// PropTypes.bool.isRequired
// PropTypes.shape({color:PropTypes.string,fontsize:PropTypes.number}) 特定规则


// 默认值
App.defaultProps={
    pageSize:10
}

组件生命周期

只有类组件有生命周期

三个阶段:创建时--》更新时--》卸载时

 创建时(挂载阶段):页面加载时,执行钩子函数

执行顺序:constructor -->render--> componentDidMount

constructor:组件创建时触发,一般解决:初始化state和处理this指向问题

render:每次组件渲染都会触发,一般解决:渲染ui但是在render不能调用setState

componentDidMount:组件挂载之后,一般解决:发送网络请求和DOM操作

更新时:导致更新的事件:new props  setState  forceUpdate

执行顺序:render--》componentDidUpdate

componentDidUpdate:组件重新渲染后(不算第一次),一般解决:发送网络请求和DOM操作,但是要使用setState一定要判断, 不然陷入死循环。可以获得上一次的props componentDidUpdate(prevprops)

componentDidUpdate(prevprops){
    if(prevprops.count!=this.props.count){
        // 网络请求
        // setState
        // 执行两次
    }
}

卸载阶段:组件从页面消失是

componentWillUnmount: 组件卸载时,一般解决清理工作:比如清理定时器。

render props---高阶组件

class Mouse extends React.Component{
    // 鼠标位置
    state ={
        x:0,
        y:0
    }
    // 鼠标移动事件的处理程序
    handleMouseMove = e =>{
        this.setState({
            x:e.clientX,
            y:e.clientY
        })
    }
    // 监听鼠标移动事件
    componentDidMount(){
        window.addEventListener('mousemove',this.handleMouseMove)
    }
    render(){
        return this.props.render(this.state)
    }
}

class Child extends React.Component{
    render(){
        return <Mouse render={(mouse)=>{
            return <p>x:{mouse.x}  y:{mouse.y}</p>
        }} />
    }
}

// children 模式
class Mouse extends React.Component{
    // 鼠标位置
    state ={
        x:0,
        y:0
    }
    // 鼠标移动事件的处理程序
    handleMouseMove = e =>{
        this.setState({
            x:e.clientX,
            y:e.clientY
        })
    }
    // 监听鼠标移动事件
    componentDidMount(){
        window.addEventListener('mousemove',this.handleMouseMove)
    }
    render(){
        return this.props.children(this.state)
    }
}

class Child extends React.Component{
    render(){
        return <Mouse>
                    {({x,y})=>{
                        <img src={img} alt="猫" />
                    }}
               </Mouse>
    }
}

// 优化 
1.对props的属性进行校验
2.在组件卸载时解除挂载的事件

高阶组件

实际是一个可以包装组件的函数

function WithMouse(WrappedComponent){
    // 调试的时候显示的名字
    Mouse.displayName='WithMouse${getDisplayName(WrappedComponent)}'
    function getDisplayName(WrappedComponent){
        return WrappedComponent.displayName || WrappedComponent.name || 'component'
    }
    class Mouse extends React.Component{
        // 鼠标位置
        state ={
            x:0,
            y:0
        }
        // 鼠标移动事件的处理程序
        handleMouseMove = e =>{
            this.setState({
                x:e.clientX,
                y:e.clientY
            })
        }
        // 监听鼠标移动事件
        componentDidMount(){
            window.addEventListener('mousemove',this.handleMouseMove)
        }
        render(){
            return <WrappedComponent {...this.state} {...this.props} ></WrappedComponent>
        }
    }
    return Mouse
}

react原理解密

setState异步更新数据

class Component extends React.component{
    state ={
        count:1
    }
    handClick = ()=>{
        // 1
        this.setState({
            count:this.count+1
        })
        console.log(this.state.count)
        // 调用handClick会打印1

        //2
        this.setState({
            count:this.count+1
        })
        console.log(this.state.count)
        this.setState({
            count:this.count+1   // 1+1
        }) 
        // 最终count为2 打印1  setState会合并更新,执行一次render更新
        // 注意后面的setState不要依赖前面setState的结果
        // setState推荐代码
        setState((state,props)=>{
            return {
                count: state.count +1
            }
        })
        // 该形式依旧是异步操作,但是两个setState的state会实时更新
        // setState的第二个参数  回调函数 会在dom渲染之后执行
        setState((state,props)=>{
            return {
                count: state.count +1
            }
        },()=>{
            console.log(state.count)
            // 打印出2
        })
    }
    render(){
        return null
    }
}

jsx语法转化过程

jsx是createELement的简化语法

jsx会被babel/preset-react转化为createElement

组件更新机制

组件更新之后,只会影响到组件和所有的后代组件

组件性能优化

1.减轻state:只存储跟组件渲染相关的数据,将没关系的数据直接挂载到this上

2.避免不必要的重新渲染:父组件的更新也会引起子组件更新, 解决方式:

//钩子函数
shouldComponentUpdate(nextProps,nextState){ // 最新的state和props
    // 可以加条件判断  if(nextState.count !== this.state.count)
    return false
}

// 执行顺序 shouldComponentUpdate -- > render

纯组件

将React.Component 换成 React.PureComponent

将shouldComponentUpdate() 的渲染问题自动解决

纯组件是浅对比----解决方法,返回新对象,不是只改变值

虚拟dom和diff算法----实现部分更新

虚拟dom使react可以脱离浏览器

react路由

功能从一个页面转到另一个页面

路由的基本使用

1.npm i react-router-dom

2.导入:import {BrowserRouter as Router, Route,Link} from  'react-router-dom'

3.Router组件包裹整个应用

4.Link 作为导航菜单 <Link to=""></Link> 

5.使用Route组件配置路由规则和要展示的组件

<Route path="" component="{}"></Route>

Router一个react应用只能有一次    或HashRouter /#/first

link 会编译成一个a标签

路由的执行过程

点击link,url会被修改,根据url中pathname将组件渲染

编程式导航

用js代码进行路由导航

this.props.history.push('/home')
this.props.history.go(-1) //-1 上一页

默认路由

<route path="/" component="{}">

精确匹配

<Route exact path="/" component="{}">

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值