1. 函数式组件
函数式组件默认return出组件模板
javascript
import './App.css';
import React from 'react';
function App(props) {
return (
<div>
hello react.js
</div>
);
}
export default App;
函数式组件的特点:
- 1.没有组件状态
- 2.没有生命周期函数
- 3.没有this,不能实例化
- 4.每次组件更新,当前函数都会执行一次。
函数式组件跟类组件的区别:
- 函数式组件内this值是undefined,不能当作当前组件实例来使用。可以通过函数调用来渲染。
- 函数式组件内部默认没有状态。
- 函数式组件内部没有生命周期。
2. hooks
useState: 用来定义组件状态,将需要定义的数据通过函数参数传递进去,返回值是一个数组,数组的第一个元素是定义的状态,第二个元素是一个函数,用来更新组件状态。
第二个参数触发组件更新,其实是重新调用函数式组件,所有组件内部的所有代码都会重新执行。
对于引用类型的值,在通过第二个参数更新的时候,需要深拷贝一下。
javascript
import './App.css';
import React, { useState } from 'react';
function App(props) {
var [count, setCount] = useState(0); //用来定义组件内部的状态
//当定义的状态是引用类型的时候需要注意,引用类型指向的是存储地址,所以将新的值传递给set函数去更新的时候,他会认为没有改变,就不会更新组件,这时候可以深拷贝一下。
var [arr, setArr] = useState([]);
var handlechange = () => {
// 修改组件状态
setCount(count + 1)
}
var handlechangeArr = () => {
arr.push(parseInt(Math.random() * 10))
setArr([...arr])
}
return (
<div>
<h1>函数式组件</h1>
<div>{count}</div>
<div>arr:{arr}</div>
<button onClick={handlechange}>改变状态</button>
<button onClick={handlechangeArr}>改变数组的值</button>
</div>
);
}
export default App;
useEffect:
用来给函数式组件添加生命周期方法。
它可以看做是 componentDidMount,componentDidUpdate和componentWillUnumount这三个生命周期函数的组合。
当useEffect函数的参数是一个回调函数时它类似于类组件中的componentDidUpdate方法,在组件每次更新的时候都执行。在参数的回调函数内return出一个函数,就会在组件卸载的时候调用,类似于类组件中的componentWillUnmount,可以用释放造成副作用的代码。
当useEffect函数的第一个参数是一个函数,第二个参数放一个空数组的时候,类似于类组件中的componentDidMount方法,在组建初次挂载的时候执行一次。数组里面也可以监听组件状态的变化,当所将领的组件状态发生改变的时候,执行回调函数。
javascript
import React, { useState, useEffect } from 'react';
// 模仿类组件的生命周期函数
//这样的写法类似于类组件中的componentDidUpadte,在组件初次渲染和更新的时候都会执行
useEffect(() => {
console.log('组件更新了')
})
// 这样的写法类似于类组件中的componentDidMount,在组件初次渲染的时候执行,只执行一次
useEffect(() => {
console.log('组件挂在了')
// 可以在这里发送请求,做事件监听,创建定时器等
//在组件卸载的时候调用执行
return ()=>{}
}, [])
// 这种写法会监听数组中的数据,当数据发生变化的时候才会执行回调函数(初次渲染也会执行)
useEffect(() => {
console.log('count发生了变化')
}, [count]) //也可以监听多个值
useRef
用来定义一个ref引用,通过ref绑定到dom节点身上,可以获取到dom节点。
javascript
import React, { useRef } from 'react';
var myref = useRef()
return (
<div>
<h1 ref={myref}>函数式组件</h1>
</div>
);
useContext: 用来接收组件通信中跨组件通信传递过来的值。由于函数式组件中没有this,所以需要用来useContext来接收。
javascript
import React, { useContext } from 'react';
import context from '../utils/context';
function Child2(props) {
var count = useContext(context)
return (
<div className='child2' style={{ border: '1px solid yellow', padding: '10px' }}>
{/* 内层组件将context绑定给组件的contextType,然后组件内部通过this.去使用
但是现在函数式组件没有this,所以需要用react提供的 useContext hook去接收
*/}
{/* <h1>child2-{this.count}</h1> */}
<h1>child2-{count}</h1>
</div>
);
}
// Child2.contextType = context;
export default Child2;
组件更新导致的重新计算: 由于组件状态更新的时候会导致函数式组件内部代码重新执行一遍,所以如果组件内部有耗时庞大的任务时,就会导致不必要的执行,可以通过useMemo去优化。
useMmemo
第一个参数是一个回调函数,会将第一个回调函数的返回值作为useMemo的返回值缓存起来。
第二个参数是一个数组,里面可以放需要监听的参数。
当监听的值发生改变的时候,才会去执行回调函数并将返回的结果缓存起来。如果没有发生变化,会直接将缓存的结果返回。
javascipt
import {useMemo} from 'react'
var result = useMemo(()=>{},[])
memo高阶组件
当父组件里面渲染子组件的时候,改变父组件状态,会导致子组件跟着更新。当子组件内部没有依赖父组件传递的数据的时候就没必要更新。
memo是一个高阶组件,它类似于类组件中的pureComponent,会对props做一个浅层比较。根据比较结果来决定是否更新子组件。
javascript
import React, {memo} from 'react'
function Child(props){
var {count} = props;
return (
<div className='chils'>
{count}
<div/>
)
}
export default memo(Child)
useCallback
如果父组件传递一个函数到子组件的时候,当父组件更新时子组件也会更新,因为函数是一个引用类型,他每次重新创建的地址都是不同的,所以子组件内部比较的时候,每次都是不一样的props。
可以借助 useCalback 钩子函数来做优化。来缓存函数定义,他只会在组件挂载的时候执行一次。这样就不会导致子组件重新更新。 原理:通过缓存第一个参数回调函数,来实现性能优化的。他的返回值是第一个参数。如果第一个参数也需要做复杂耗时的任务,也可以把需要依赖的值放在第二个参数的数组里面。当第二个参数依赖的值没有发生变化,就不会重新定义。
javascript
import React ,{useCallback} from 'react'
function App(props){
var saveIndex = useCallback(()=>{
console.log("传递给子组件的函数")
},[])
return (
<div>
<Child callback = {saveIndex}/>
<div/>
)
}
export default App;
hooks使用规则
hook的本质就是一个javascript函数,在使用它的时候需要遵循两条规则:
只在最顶层使用hook: 不要再循环,条件或嵌套函数中调用hook。确保你总是在顶层使用hook。
只在react函数中使用hook: 不要普通的js函数中调用。
- 在函数式组件中去调用。
- 在自定义hook中去调用。
3.自定义hook
将高度耦合通用性比较高的代码封装到一个hook中,hook命名一般是以use开头。
javascript
import {useEffect,useState} from 'react'
// 封装一个自定义hook
export function useRequest(){
var [list,setList] = useState([])
useEffect(()=>{
// 发请求去获取数据
},[])
return [list,setList]
}