20200129-React基础-高级应用

一、组合与继承

  1. 概念:将组件的开标签与闭标签之间的内容展示在组件的内部进行展示,通过prop传递。(父组件中定义子组件的内容,类似于vue中的插槽slot)
  2. 形式
  • 包含关系
  • 渲染其他组件
//父组件
import ChildA from './childA.jsx'

class Father extends Component {
    state = {}
    render(){
        let Acom = <a href="#">这是一个a标签组件</a>
        return <div className="extend-father" style={{border:'1px solid #000'}}>
            father content
            <ChildA Acom={Acom}>
                <h1>包含关系:嵌入内容</h1>
            </ChildA>

        </div>
    }
}
// 子组件
class ChildA extends Component {
    constructor(props){
        super(props)
        this.state = {}
    }
    render(){
        return <div style={{backgroundColor:'orange'}}>
            hello world!
            {/* 包含关系 */}
            {this.props.children}
            {/* 渲染其他组件 */}
            {this.props.Acom}
        </div>
    }
}

二、错误边界处理

  1. 概念:错误边界其实就是一种组件,可以捕获并打印发生在其子组件树任何位置的javascript错误,并且,他会渲染出备用ui.
  2. 处理
  • Static getDerivedStateFromError() //渲染备用ui
  • componentDidCatch() //打印错误信息
  1. 注意事项:下面这些错误无法捕获到的
  • 事件处理
  • 异步代码
  • 服务端渲染
  • 它自身抛出来的错误
  1. 使用
//错误边界组件
class ErrorBoundary extends Component {
    constructor(props) {
        super(props);
        this.state = { hasError: false };
    }

    static getDerivedStateFromError(error) {
        // 更新 state 使下一次渲染能够显示降级后的 UI
        return { hasError: true };
        
    }

    componentDidCatch(error, info) {
        // 你同样可以将错误日志上报给服务器
        console.log(error, info)
    }

    render() {
        if (this.state.hasError) {
            return <h1>Something went wrong.</h1>;
        }
        return this.props.children;
    }
}

// 父组件
// Error是想要显示的组件,ErrorBoundary是错误边界组件,如果有错,那么就不会渲染Error组件
render() {
  return <ErrorBoundary>
    <Error />
  </ErrorBoundary>
}

三、高阶组件应用

  1. 概念:高阶组件(HOC)是react中对组件逻辑进行重用的高级技术,但是高阶组件本身并不是React的API,它只是一种模式,这种模式是由react自身的组合性质必然产生的。
  2. 作用
  • 公共业务逻辑的提取,服用
  • 渲染的劫持
  1. 使用:传入高阶函数一个组件,处理之后返回一个新的组件
  2. 注意事项
  • 不可以改变原始组件
  • 不要在render方法中使用HOC
  • refs不会被传递(React.forwardRef)

// 渲染一个列表,使用hoc分离数据请求和渲染。思路:将请求数据封装成一个高阶组件,将排序也封装成一个高阶组件,然后渲染组件作为参数传递给高阶组件
/*渲染组件*/
import HocSortList from './hocSortList.jsx'

class List extends Component {
    constructor(props){
        super(props)
        this.state = {}
    }
   render(){
        return <div className="list">
            <ul>
                {this.props.list.map((item,index) => <li key={index}>{item.name}---{item.age}</li>)}
            </ul>
        </div>
   }
}
export default HocGetData(HocSortList(List))
/*请求数据高阶组件*/
function HocGetData(Com){
    return class extends Component{
        constructor(props){
            super(props)
            this.state = {
                loading:true,
                list:[]
            }
        }
        componentDidMount(){
            setTimeout(()=>{
                this.setState({
                    list:[
                        {name:'xm',age:18},
                        {name:'xh',age:19},
                        {name:'xl',age:17},
                        {name:'xx',age:9},
                    ],
                    loading:false
                })
            },3000)
        }
        render(){
            return this.state.loading ? <p>正在加载...</p>:<Com list={this.state.list}/>
        }
    }
}
export default HocGetData
/*排序高阶组件*/
function HocSortList(Com){
    return class extends Component {
        constructor(props){
            super(props)
            this.state = {
                list:[...props.list]
            }
            this.state.list.sort((a,b)=>{
                return a.age - b.age
            })
        }
        render(){
            return <Com list={this.state.list} />
        }
    }
}

export default HocSortList

四、Refs and the Dom

  1. 应用场景
  • 焦点,文本选择或媒体播放
  • 动画效果或者第三方动画库需要dom操作
  1. 使用
  • 通过React.creatRef()创建ref
  • 通过current属性获取dom
  1. 注意事项
  • 尽量不要将ref暴露给父组件
  • 给一个类组件绑定ref获取到的是类的实例,给函数组件绑定ref会报错,所以衍生出下面一条
  • 只能在class类组件中使用。(函数组件内部可以使用,不要理解错了)
import React , {Component , useEffect} from 'react'
/*类组件*/
class RefCom extends Component {
    constructor(props){
        super(props)
        this.state = {
            inpRef : React.createRef()
        }
    }
    componentDidMount(){
        console.log(this.state.inpRef);
        this.state.inpRef.current.focus()
    }
   render(){
        return <div>
            <p>类组件中的dom操作</p>
            <input type="text" ref={this.state.inpRef}/>
        </div>
   }
}
/*函数组件*/
// function RefCom(){
//     let inpRef = React.createRef()
//     useEffect(() => {
//         console.log(inpRef.current);
//         inpRef.current.focus()
//     },[])
//     return <div>
//         <p>函数组件中的dom操作</p>
//         <input type="text" ref={inpRef}/>
//     </div>
// }
export default RefCom

五、最新Hooks基础应用

  1. Hook概念
  • 在react16.8中新增的钩子函数
  • 为函数式组件提供了更多的逻辑操作戒口
  • 可以在编写class的情况下使用state
  1. 为什么使用
  • 解决了组件之前服用状态逻辑的难点
  • 降低了react中使用class的学习成本
  • 可以与clas组件完美的结合
  • 拥抱函数式变成
  • 解决了难以理解的生命周期问题
  1. useState
  • 支持传入任何数据类型作为初始值
  • 返回一个数组,具有两个参数
    • 第一个参数为数据监听值,相当于定义的state中的数据
    • 第二个参数为改变数据的函数,相当于setState,但不会合并state
  • 支持惰性求职,使用时才进行useState参数的执行(改变不执行)
  • 可以在一个函数式组件使用多次
  1. useEffect
  • 副作用钩子函数
  • 代替了componentDidMount、componentDidUpdate和componentWillUnmount生命周期函数
  • 可以访问props和state
  • 通过返回一个函数来清除副作用
  • 第二参数可以指定依赖项,可以通过数组指定多个依赖项,如果为空数组则相当于componentDidMount
import React , {useState , useEffect} from 'react'

function BaseHook(){
    const [data , putData] = useState(0)
    const [num , putNum] = useState(() => {
        return 77
    })
    //第二个参数为空数组相当于componentDidMount函数
    useEffect(()=>{
        console.log(data);
        console.log(num);
        let timer = setInterval(() => {
            console.log('111');
        }, 1000);
        //这里的return相当于componentWillUnmount
        return () => {
            clearInterval(timer)
        }
    },[])
    // 相当于componentDidUpdate
    useEffect(() => {
        console.log('=====num 改变了',num);
    } , [num])
    return <div>
        <p>hooks的基础应用</p>
        <p>{num}</p>
        <p onClick={() => {putNum(Math.random())}}>点击改变num</p>

    </div>
}

六、最新Hokks高级应用

  1. 自定义Hooks
    理解:就是将公共逻辑抽取封装成一个函数类,通过传入回调来得到想要的内容
    demo:封装一个获取当前时间戳的公共逻辑
//代码查看文件
//base-project/src/components/highHook/custom.jsx
//base-project/src/components/highHook/time.jsx
  1. useContext
  • 定义当前组件的上下文
  • 当前组件接受最近的上层组件<MyContext.Provider>的值
  • 当前组件会跟随上层组件的数据更新而更新
//代码查看文件
//base-project/src/components/highHook/useContext.jsx
  1. useReducer
  • 概要
    • useState的代替方案
    • 接受一个形如(state,action) => newState的reducer
    • 返回一个state数据和dispatch方法
    • 第一个参数为reducer纯函数,第二个参数为初始值,第三个参数为初始化函数
    • 跳过dispathc(内部使用Objeect.is进行对比)
  • 使用场景
    • 多种逻辑操作
    • 新的state依赖旧的state
    • 多组件间的通讯
//代码查看文件
//base-project/src/components/highHook/useReducer.jsx
  1. useCallback和useMemo
  • useCallback
    • 与useEffect有类似的功能,检测某些值改变的时候执行回到函数
    • 第二个参数为依赖值,数组为空时候,代表不依赖任何职,智慧之星一次
    • 不要在此函数进行副作用操作
    • 此函数适合进行某些计算或者渲染
  • useMemo
    • 用意跟useCallback使用相同
    • useCallback(fn,deps)相当于useMemo(()=>fn ,deps)
//代码查看文件
//base-project/src/components/highHook/useCallback.jsx
  1. useRef
  • useRef返回一个可变的ref对象
  • 返回的ref对象在组件的整个生命周期内保持不变
  • ref对象.current属性设置为相应的Dom节点
  • 当ref对象内容发生变化时,useRef并不会通知你
  • 变更.current属性不会引发组件重新渲染
//代码查看文件
//base-project/src/components/highHook/useRef.jsx
  1. useLayoutEffect
  • 与useEffect类似
  • 区别:
    • useEffect在render结束后,就会执行回调函数,并不会阻塞浏览器绘制(异步操作。ps:类组件中的componentDidMount和componentDidUpdate是同步)
    • useLayoutEffect就是当你需要在回调里面做dom操作的时候,他会立即执行回调函数,但是会在浏览器进行任何绘制之前完成
发布了12 篇原创文章 · 获赞 2 · 访问量 143

猜你喜欢

转载自blog.csdn.net/www_lin/article/details/104650654
今日推荐