react条件渲染,循环,父子组件传值,生命周期, 插槽,React.lazy懒加载优化

一、条件渲染的三种方式

1. 三元表达式

 // 构造器
    constructor() {
        super();
        this.state = {
            bShow: true
        }
    }
    
 // 在render函数return中判断
 {this.state.bShow ? <div className={'box'}/> :''}
复制代码

2. &&运算符

 {this.state.bShow && <div className={'box'}/>}
复制代码

3. if判断

// 在render函数return外判断
 let box2 = ''
        if (this.state.bShow) {
            box2 = <div className={'box'}/>
        }
复制代码

页面代码

import React from 'react'
import HeaderComponent from './component/header'
import  ReactDom from 'react-dom'
import './assets/css/app.css'

class App extends React.Component {
    // 构造器
    constructor() {
        super();
        this.state = {
            bShow: true
        }
    }

    // 生命周期钩子
    componentDidMount() {
        // console.log(this.refs.node.innerHTML)
        console.log(document.getElementById('header'))
        console.log(ReactDom.findDOMNode(document.getElementById('header')))
    }

    // 渲染dom
    render() {
        let username = '张三'
        let content = "<span style='color: #ff0000'>搞颜色</span>"
        let box2 = ''
        if (this.state.bShow) {
            box2 = <div className={'box'}/>
        }
        return (
            <div className="App">
                {/*头部组件*/}
                <HeaderComponent />
                {username}
                <div dangerouslySetInnerHTML={{__html: content}}/>
                {/*<div ref="node">节点信息</div>*/}
                {this.state.bShow ? <div className={'box'}/> :''}
                <br/>
                {this.state.bShow && <div className={'box'}/>}
                <br/>
                {box2}
            </div>
        )
    }
}

export default App;

复制代码
效果如下

image.png

二、 点击事件

  // 在类中定义事件 改变盒子显示/隐藏
    change() {
        this.setState({bShow: !this.state.bShow})
    }
    // 在return中通过bind(this)去调用事件
    {/*显示隐藏*/}
     <button onClick={this.change.bind(this)} >显示/隐藏</button>
复制代码

三、 列表循环

1. 在state中定义一个数组

 this.state = {
            // 盒子显示隐藏
            bShow: true,
            // 商品数据
            aGoods: [
                {id:1,title:'潮流女装'},
                {id:2,title:'品牌男装'},
                {id:3,title:'手机电脑'}
            ]
        }
复制代码

2. 在render函数中用es6的map方法渲染

 <ul>
    {this.state.aGoods.map((v ,i)=> (
        <li key={i}>{v.title}</li>
    ))}
</ul>
复制代码

效果

image.png

三、父子组件传值

1. 父组件通过属性形式传值

  {/*头部组件*/}
   <HeaderComponent title="头部子组件" />
复制代码

2. 子组件通过props接收

image.png

效果

image.png

3. 限制props参数类型

3-1 引入prop-types
import PropsType from 'prop-types'
复制代码
3-2 定义组件的propTypes
HeaderComponent.propTypes = {
    title: PropsType.number
}
复制代码

效果如下 定义的是数值类型, 传入的是字符串报错

image.png

4. 参数必填项: isRequired

HeaderComponent.propTypes = {
    title: PropsType.string.isRequired
}
复制代码

5. 参数默认值

HeaderComponent.defaultProps = {
    title: '默认子组件值'
}
复制代码
  {/*头部组件*/}
   <HeaderComponent  />
复制代码

效果

image.png

6. 父子组件的例子, 父组件控制子组件的显示隐藏

import React from 'react'
import HeaderComponent from './component/header'
import  ReactDom from 'react-dom'
import './assets/css/app.css'

class App extends React.Component {
    // 构造器
    constructor() {
        super();
        this.state = {
            // 盒子显示隐藏
            bShow: true,
            // 商品数据
            aGoods: [
                {id:1,title:'潮流女装'},
                {id:2,title:'品牌男装'},
                {id:3,title:'手机电脑'}
            ],
            // 子组件盒子的显示隐藏
            childShow: true
        }
    }

    // 生命周期钩子
    componentDidMount() {
        // console.log(this.refs.node.innerHTML)
        // console.log(document.getElementById('header'))
        console.log(ReactDom.findDOMNode(document.getElementById('header')))
    }

    // 改变盒子显示/隐藏
    change() {
        this.setState({bShow: !this.state.bShow})
    }

    // 改变盒子显示/隐藏
    changeChildComponent() {
        this.setState({childShow: !this.state.childShow})
    }

    // 渲染dom
    render() {
        let username = '张三'
        let content = "<span style='color: #ff0000'>搞颜色</span>"
        let box2 = ''
        if (this.state.bShow) {
            box2 = <div className={'box'}/>
        }
        return (
            <div className="App">
                {/*显示子隐藏*/}
                <button onClick={this.changeChildComponent.bind(this)} >显示/隐藏</button>
                {/*头部组件*/}
                <HeaderComponent title="头部子组件" isShow={this.state.childShow} />
                {username}
                <div dangerouslySetInnerHTML={{__html: content}}/>
                {/*显示隐藏*/}
                <button onClick={this.change.bind(this)} >显示/隐藏</button>
                {/*<div ref="node">节点信息</div>*/}
                {this.state.bShow ? <div className={'box'}/> :''}
                <br/>
                {this.state.bShow && <div className={'box'}/>}
                <br/>
                {box2}
                <ul>
                    {this.state.aGoods.map((v ,i)=> (
                        <li key={i}>{v.title}</li>
                    ))}
                </ul>
            </div>
        )
    }
}

export default App;

复制代码
import React,{Component} from  'react'
import PropsType from 'prop-types'

class HeaderComponent extends Component{
    render() {
        return (
            <div id="header" style={this.props.isShow ? {display: "block"} : {display: 'none'}}>{this.props.title}</div>
        )
    }
}

HeaderComponent.propTypes = {
    title: PropsType.string.isRequired,
    isShow: PropsType.bool
}

HeaderComponent.defaultProps = {
    title: '默认子组件值',
    isShow: true
}

export default HeaderComponent

复制代码

效果如下

image.png

源码中propTypes的类型:

image.png

7. 面试题state和props的区别

state和props主要区别于props是不可变的, 而state可以根据于用户交互来改变。这就是为什么有些容器组件需要定义state来更新和修改数据。而子组件只能通过props来传递数据。
复制代码

7.1 面试题在React, 何为state?

状态是React组件的和兴, 是数据的来源, 必须尽可能简单. 基本上状态是确定组件呈现和行为的对象. 与props不同, 他们是可变的, 并创建动态和交互式组件, 可以通过this.state访问他们
复制代码

7.2 面试题在构造函数中调用super(props)的目的是什么?

在super(被调用之前), 子类是不能使用this的, 在ES2015中, 子类必须在constructor中调用super(). 传递props给super()的原因则是便于(在子类中)能在constructor访问props
复制代码

7.3 面试题setState的第二个参数是异步回调函数

// 按钮文案
btnText: '原按钮'

 // 改变按钮的文案
changeBtnText() {
    this.setState({btnText: '新文案'}, () => {
        console.log(this.state.btnText)
    })
}

<button onClick={this.changeBtnText.bind(this)}>{this.state.btnText}</button>
复制代码

image.png

7.4 面试题为什么onClick调用方法还有通过bind(this)去调用

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <script>
        function Obj() {
            this.username = '张三'
            this.init()
        }
        Obj.prototype.init = function () {
            console.log(this)
            document.addEventListener('click', function () {
                console.log(this)
            })
        }
        new Obj()
    </script>
</body>
</html>

复制代码

显然第一次打印this指向Obj, 第二次就指向document

image.png

通过bind(this)This就指向Obj了

   document.addEventListener('click', function () {
                console.log(this.username)
            }.bind(this))
复制代码

image.png

通过es6箭头函数就不会改变this指向从而直接调用

 document.addEventListener('click', () => {
                console.log(this.username)
            })
复制代码

image.png

八、生命周期钩子

 // 页面将要加载(不安全即将弃用) 
    componentWillMount () {
        console.log('componentWillMount')
    }

    // 在组件接收到一个新的props时被调用. 这个方法在render时不会被调用(不安全即将弃用)
    componentWillReceiveProps(nextProps, nextContext) {
        console.log('componentWillReceiveProps',nextProps)
    }

    // 页面渲染完成
    componentDidMount() {
        // console.log(this.refs.node.innerHTML)
        // console.log(document.getElementById('header'))
        console.log(ReactDom.findDOMNode(document.getElementById('header')))
    }

    // 返回一个布尔值. false为不更新组件, true为更新, 在组件接收到新的props或者state时被调用. 在初始化时不被调用. 可以再你确认不需要更新组件时使用. 用户优化
    shouldComponentUpdate(nextProps, nextState, nextContext) {
       return this.state.bShow !== nextState.bShow;
    }
    
     // 组件将要更新
    componentWillUpdate(nextProps, nextState, nextContext) {
        console.log('componentWillUpdate',nextProps,nextState)
    }

    // 在组件完成更新后立即调用. 在初始化时不会被调用
    componentDidUpdate(prevProps, prevState, snapshot) {
        console.log('componentDidUpdate', prevProps, prevState)
    }
    
     // 组件从dom中移除的时候立即被调用. (当离开页面的时候被调用)
    componentWillUnmount() {
        console.log('componentWillUnmount')
    }

复制代码

image.png

九、子组件给父组件传值

1.在子组件中通过props中的方法发送

 <button onClick={this.props.sendParent.bind(this,'发送消息给父组件')}>发送消息给父组件</button>
复制代码

2. 在父组件中通过sendParent接收消息

HeaderComponent isShow={true} sendParent={this.getChildren.bind(this)} />
复制代码
效果
复制代码

image.png

3. 如果子组件不需要传值可以不绑定this

<button onClick={this.props.onClick}>保存</button>
复制代码
 <HeaderComponent isShow={true} sendParent={this.getChildren.bind(this)} onClick={this.saveData.bind(this)} />
  // 子组件保存数据
    saveData() {
        console.log('保存数据...')
    }
复制代码

效果

image.png

4. 子组件的input输入框通过onChange实现数据的双向绑定

子组件中

 <input onChange={this.props.onChange}/>
复制代码

父组件中

<Input onChange={(e)=>{this.setState({iptValue:e.target.value})}}/>
<br/>
{this.state.iptValue}
复制代码
效果

image.png

十、插槽

1. 通过childre去接收参数

例如封装一个button组件

import React, {Component} from 'react'

class Button extends Component {
    render() {
        console.log(this.props.children)
        return (
            <React.Fragment>
               <button type={this.props.type}>{this.props.children}</button>
            </React.Fragment>
        )
    }
}

Button.defaultProps = {
    type: 'button'
}

export default Button

复制代码

父组件中

 <form action={'http://www.baidu.com'} target={'_blank'}>
    <input type="text"/>
    <Button type={"submit"}>提交  </Button>
    <Button type={"reset"}>重置</Button>
    <Button>删除</Button>
    <Button>修改</Button>
</form>
复制代码

效果

image.png

注意如果插槽有多个节点childre接收的是一个数组

image.png

 <Button type={"submit"}>提交 <span>123</span> </Button>
复制代码

3. 利用插槽重新className和style

3.1 子组件中

import React, {Component} from 'react'
import './style.css'

class Button extends Component {
    render() {
        console.log(this.props.children)
        return (
            <React.Fragment>
               <button type={this.props.type} className={'my-button '+ this.props.className} style={this.props.style}>{this.props.children}</button>
            </React.Fragment>
        )
    }
}

Button.defaultProps = {
    type: 'button'
}

export default Button

复制代码

父组件中

import React from 'react'
import Button from  './component/button'
import './assets/css/app.css'

class App extends React.Component {
    // 构造器
    constructor() {
        super();
        this.state = {

        }
    }



    // 渲染dom
    render() {
        return (
            <div className="App">
                <form action={'http://www.baidu.com'} target={'_blank'}>
                    <input type="text"/>
                        <Button type={"submit"}>提交 <span>123</span> </Button>
                    <Button type={"reset"}>重置</Button>
                    <Button className={'btn-danger'} style={{height:'200px'}}>删除</Button>
                    <Button>修改</Button>
                </form>
            </div>
        )
    }
}

export default App;

复制代码

效果

image.png

十一、 优化相关

1. React.lazy()(16.6以后的版本)

lazy(方法是用来对项目diamante进行分割, 懒加载用的. 只有当组件被加载, 内部的资源才会导入.为什么需要懒加载?)
在react的项目中import导入其他组件和库都是默认在初始直接导入的, webpack等打包工具会将import导入的文件直接合并到一个大文件中,入股哦项目很大, 打包完后初始化加载需要加载的文件会很大, 这时候就需要代码分割
复制代码

2.React.Suspense()(16,6以后的版本)

Suspense的作用就是在遇到异步请求或者异步导入组件的时候等待请求和导入完成在进行渲染

3 使用lazy和suspense优化Input组件的懒加载

import React, {lazy,Suspense} from 'react'
import Button from  './component/button'
import './assets/css/app.css'
const Input = lazy(()=>import('./component/Input'))

class App extends React.Component {
    // 构造器
    constructor() {
        super();
        this.state = {
            iptShow: false
        }
    }



    // 渲染dom
    render() {
        return (
            <div className="App">
                <form action={'http://www.baidu.com'} target={'_blank'}>
                    {this.state.iptShow &&
                     <Suspense fallback={<React.Fragment />}>
                         <Input />
                     </Suspense>
                    }
                    <Button type={"submit"}>提交 <span>123</span> </Button>
                    <Button type={"reset"}>重置</Button>
                    <Button className={'btn-danger'} >删除</Button>
                    <Button>修改</Button>
                    <Button onClick={()=>{this.setState({iptShow: !this.state.iptShow})}}>显示/隐藏</Button>
                </form>
            </div>
        )
    }
}

export default App;

复制代码

开始js只加载了3个文件

image.png

当点击显示Input组件的时候才会加载另外一个js文件

image.png

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享