一、组合与继承
- 概念:将组件的开标签与闭标签之间的内容展示在组件的内部进行展示,通过prop传递。(父组件中定义子组件的内容,类似于vue中的插槽slot)
- 形式
//父组件
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>
}
}
二、错误边界处理
- 概念:错误边界其实就是一种组件,可以捕获并打印发生在其子组件树任何位置的javascript错误,并且,他会渲染出备用ui.
- 处理
- Static getDerivedStateFromError() //渲染备用ui
- componentDidCatch() //打印错误信息
- 注意事项:下面这些错误无法捕获到的
- 事件处理
- 异步代码
- 服务端渲染
- 它自身抛出来的错误
- 使用
//错误边界组件
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>
}
三、高阶组件应用
- 概念:高阶组件(HOC)是react中对组件逻辑进行重用的高级技术,但是高阶组件本身并不是React的API,它只是一种模式,这种模式是由react自身的组合性质必然产生的。
- 作用
- 使用:传入高阶函数一个组件,处理之后返回一个新的组件
- 注意事项
- 不可以改变原始组件
- 不要在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
- 应用场景
- 焦点,文本选择或媒体播放
- 动画效果或者第三方动画库需要dom操作
- 使用
- 通过React.creatRef()创建ref
- 通过current属性获取dom
- 注意事项
- 尽量不要将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基础应用
- Hook概念
- 在react16.8中新增的钩子函数
- 为函数式组件提供了更多的逻辑操作戒口
- 可以在编写class的情况下使用state
- 为什么使用
- 解决了组件之前服用状态逻辑的难点
- 降低了react中使用class的学习成本
- 可以与clas组件完美的结合
- 拥抱函数式变成
- 解决了难以理解的生命周期问题
- useState
- 支持传入任何数据类型作为初始值
- 返回一个数组,具有两个参数
- 第一个参数为数据监听值,相当于定义的state中的数据
- 第二个参数为改变数据的函数,相当于setState,但不会合并state
- 支持惰性求职,使用时才进行useState参数的执行(改变不执行)
- 可以在一个函数式组件使用多次
- 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高级应用
- 自定义Hooks
理解:就是将公共逻辑抽取封装成一个函数类,通过传入回调来得到想要的内容
demo:封装一个获取当前时间戳的公共逻辑
//代码查看文件
//base-project/src/components/highHook/custom.jsx
//base-project/src/components/highHook/time.jsx
- useContext
- 定义当前组件的上下文
- 当前组件接受最近的上层组件<MyContext.Provider>的值
- 当前组件会跟随上层组件的数据更新而更新
//代码查看文件
//base-project/src/components/highHook/useContext.jsx
- useReducer
- 概要
- useState的代替方案
- 接受一个形如(state,action) => newState的reducer
- 返回一个state数据和dispatch方法
- 第一个参数为reducer纯函数,第二个参数为初始值,第三个参数为初始化函数
- 跳过dispathc(内部使用Objeect.is进行对比)
- 使用场景
- 多种逻辑操作
- 新的state依赖旧的state
- 多组件间的通讯
//代码查看文件
//base-project/src/components/highHook/useReducer.jsx
- useCallback和useMemo
- useCallback
- 与useEffect有类似的功能,检测某些值改变的时候执行回到函数
- 第二个参数为依赖值,数组为空时候,代表不依赖任何职,智慧之星一次
- 不要在此函数进行副作用操作
- 此函数适合进行某些计算或者渲染
- useMemo
- 用意跟useCallback使用相同
- useCallback(fn,deps)相当于useMemo(()=>fn ,deps)
//代码查看文件
//base-project/src/components/highHook/useCallback.jsx
- useRef
- useRef返回一个可变的ref对象
- 返回的ref对象在组件的整个生命周期内保持不变
- ref对象.current属性设置为相应的Dom节点
- 当ref对象内容发生变化时,useRef并不会通知你
- 变更.current属性不会引发组件重新渲染
//代码查看文件
//base-project/src/components/highHook/useRef.jsx
- useLayoutEffect
- 与useEffect类似
- 区别:
- useEffect在render结束后,就会执行回调函数,并不会阻塞浏览器绘制(异步操作。ps:类组件中的componentDidMount和componentDidUpdate是同步)
- useLayoutEffect就是当你需要在回调里面做dom操作的时候,他会立即执行回调函数,但是会在浏览器进行任何绘制之前完成