本文已参与[新人创作礼]活动,一起开启掘金创作之路
一 hooks
1.是什么
是钩子,是React 16.8的新特性
2.为什么
可以让函数组件使用state及其他的React特性,如生命周期等
3.怎么用
import React,{useState} from 'react'
const Func = () => {
const [color,setColor]=useState('red')
return (
<div>
<button onClick={()=>setColor('green')}></button>
{color}
</div>
)
};
export default Func
4.好处
1 组件的状态逻辑复用
2 避免了class 组件自身的问题
5.场景
在使用函数组件时需要状态时或给函数选择执行时机时使用
6.原理
是一些可以让你在函数组件里“钩入” React state 及生命周期等特性的函数
二 useState
1.为什么
为函数组件提供状态
2.怎么用
-
导入
useState函数 -
调用
useState函数,传入初始值,返回状态和修改状态的函数 -
使用
-
在 JSX 中展示
状态 -
特定的时机调用修改状态的函数来改状态
-
import React,{useState} from 'react'
const Func = () => {
const [color,setColor]=useState('red')
return (
<div>
<button onClick={()=>setColor('green')}></button>
{color}
</div>
)
};
export default Func
3.注意
(1)参数:状态初始值。比如,传入 0 表示该状态的初始值为 0
(2)此处的状态可以是任意值(比如,数值、字符串等),而 class 组件中的 state 必须是对象
(3)返回值:数组,包含两个值:1 状态值(state) 2 修改该状态的函数(setState)
(4)修改该状态的函数中参数
/1/值
const [count, setCount] = useState(0)
/2/回调函数
需要return,注意箭头函数内部形参的使用,给状态值多次修改会出现覆盖的效果
4.更新机制
(1)状态更新,整个组件的逻辑重新运行一次;
(2)useState只会在组件第一次渲染时使用状态的初值,随后都会使用状态的最新值
(3)useState 这个 Hook 就是用来管理 state 的,它可以让函数组件具有维持状态的能力。也就是说,在一个函数组件的多次渲染之间,这个 state 是共享的。
三 useEffect
0.什么是副作用
对于react组件来说,除了渲染UI之外的其他操作,都可以称之为副作用
2.为什么
处理函数组件中的副作用
3.执行时机
render工作完成之后,执行Effect;
如果定义了多个,则顺序执行
4.怎么用
(1)参数
参数1,副作用函数
参数2,执行副作用函数的依赖项,他决定了什么时机执行参数1
使用分析
-
1.若不带第二个参数。执行时机,初次执行以及每次更新之后都会执行,模拟componentDidMount+componentDidUpdate
-
2.若带第二个参数。参数是空数组,初始执行,模拟componentDidMount
-
3.若带第二个参数。并指定依赖项。执行时机(1)初始执行(2)依赖项的值发生变化时执行一次,模拟componentDidMount+指定依赖项的监听
-
4.依赖项为空,没有具体的副作用函数,有副作用函数的清理函数。将要卸载组件前,模拟componentWillUnMount
(2)函数
effect只能是同步函数,不能使用async
(3)案例1:发请求
import React,{ useEffect,useState } from 'react'
import axios from 'axios'
const Func = () => {
const [count,setCount]=useState(0)
const [list,setList]=useState([])
useEffect(()=>{
console.log('1');
axios
.get('****').then((res)=>{
console.log('88',res);
setList(res.data.result)
})
},[])
useEffect(()=>{
console.log('2');
},[count])
console.log(list,'x');
return <div>
====={count}==========
<ul>
{list.map((item)=>{
return <li key={item.id}>{item.name}</li>
})}
</ul>
<button onClick={()=>setCount(count+1)}>按钮</button>
</div>
};
export default Func
(3)案例2:全选,单选互相影响,持久化存储
要求:
MyFooter需要传输list列表数据,changeAll全选,flag单个状态 GoodsItem需要传输每一项列表信息item及给每一项绑定change事件changeHandle
思路展示:
效果展示:
代码展示:
import React, { useEffect, useState } from 'react'
import MyHeader from './MyHeader'
import MyFooter from './MyFooter'
import GoodsItem from './GoodsItem'
import 'bootstrap/dist/css/bootstrap.css'
import './shop.css'
export default function Shop() {
const arr = [
{
{
id: 10,
goods_name:
'Semir森马卫衣女冬装2019新款可爱甜美大撞色小清新连帽薄绒女士套头衫',
goods_img: 'https://www.escook.cn/vuebase/pics/10.png',
goods_price: 153,
goods_count: 1,
goods_state: false,
},
...
]
const [list, setList] = useState(
JSON.parse(localStorage.getItem('list')) || arr
)
const [flag, setFlag] = useState(false)
/* 全选的切换显示 */
const changeAll = (flag) => {
/* 更改全选状态值 */
setFlag(flag)
/* 2-实现全选 */
// list.forEach((item) => {
// item.goods_state = flag
// })
setList(() => {
var newList = list.map((item) => {
return {
...item,
goods_state: flag,
}
})
//3- 做持久化
localStorage.setItem('list', JSON.stringify(newList))
return newList
})
}
/* 4-实现点个状态改变 */
const changeHandle = (id, state) => {
console.log(id, state, 8888)
// 更新当前状态
// var itemObj = list.find((item) => item.id === id)
// console.log(itemObj, 87)
// itemObj.goods_state = state
setList(() => {
var newList = list.map((item) => {
if (item.id === id) {
return {
...item,
goods_state: state,
}
} else {
return { ...item }
}
})
return newList
})
}
useEffect(() => {
// 循环 判断每一项的状态是不是都是true或者false===实现反选
var bool = list.every((item) => item.goods_state)
/* 更改全选状态值 */
setFlag(bool)
}, [list])
return (
<div className="app">
<MyHeader>购物车</MyHeader>
{list.map((item) => {
return (
<GoodsItem
key={item.id}
{...item}
changeHandle={changeHandle}
></GoodsItem>
)
})}
<MyFooter list={list} changeAll={changeAll} flag={flag}></MyFooter>
</div>
)
}
(4) 副作用函数的返回值-清除副作用
格式1:
useEffect(() => {
// 副作用函数的内容
return 副作用函数的返回值
}, [])
格式2:
useEffect(() => {
// 副作用函数的内容
return ()=>{ /* 做清理工作*/ } // 清理函数
}, [])
清理函数的执行时机
清理函数会在组件卸载时以及下一次副作用函数调用之前执行
错误实例
import React, { useEffect, useState } from 'react'
import ReactDom from 'react-dom'
function Com1 () {
useEffect(() => {
window.addEventListener('mousemove', (e) => {
console.log(e.pageX, e.pageY)
})
}, [])
return <div>子组件</div>
}
export default function App () {
const [isShow, setIsShow] = useState(true)
return (
<div>
{isShow && <Com1 />}
<button onClick={() => setIsShow(!isShow)}>切换</button>
</div>
)
}
ReactDom.render(<App />, document.getElementById('root'))
正确实例
import React, { useEffect, useState } from 'react'
import ReactDom from 'react-dom'
function Com1 () {
useEffect(() => {
const fn = (e) => {
console.log(e.pageX, e.pageY)
}
+ window.addEventListener('mousemove', fn)
+ return () => {
window.removeEventListener('mousemove', fn)
console.log('组件删除了')
}
}, [])
return <div>子组件</div>
}
export default function App () {
const [isShow, setIsShow] = useState(true)
return (
<div>
{isShow && <Com1 />}
<button onClick={() => setIsShow(!isShow)}>切换</button>
</div>
)
}
ReactDom.render(<App />, document.getElementById('root'))
四 自定义hooks
1.是什么
- 自定义 Hooks 是一个函数,约定函数名称必须以 use 开头,React 就是通过函数名称是否以 use 开头来判断是不是 Hooks
- Hooks 只能在函数组件中或其他自定义 Hooks 中使用,否则,会报错!
- 自定义 Hooks 用来提取组件的状态逻辑,根据不同功能可以有不同的参数和返回值(就像使用普通函数一样)
2.为什么
自定义 Hooks 针对不同组件实现不同状态逻辑复用。
3.场景
将组件状态逻辑提取到可重用的函数(自定义 Hooks)中,实现状态逻辑复用。
4.怎么用
Bpp.js
// useMouse.js
import { useEffect, useState } from 'react'
export default function useMouse() {
// 逻辑处理
const [position, setPosition] = useState({
x: 0,
y: 0,
})
useEffect(() => {
const move = (e) => {
setPosition({
x: e.pageX,
y: e.pageY,
})
}
document.addEventListener('mousemove', move)
return () => {
document.removeEventListener('mousemove', move)
}
}, [])
// 返回状态
return position
}
App.js
import React from 'react'
import useMouse from './Bpp'
function Com () {
const position = useMouse()
console.log(position);
return <div>
{position.x}
<br/>
{position.y}
</div>
}
export default Com
五 useRef
1.是什么
使用场景:在 React 中进行 DOM 操作时,用来获取 DOM
作用:返回一个带有 current 属性的可变对象,通过该对象就可以进行 DOM 操作了。
3.怎么用
- 参数:在获取 DOM 时,一般都设置为 null
- 返回值:包含 current 属性的对象。
- 注意:只要在 React 中进行 DOM 操作,都可以通过 useRef Hook 来获取 DOM(比如,获取 DOM 的宽高等)。
- 注意:useRef不仅仅可以用于操作DOM,还可以操作组件
简单使用
// 1. 导入 useRef
import React, { useRef } from 'react'
const Func = () => {
// 2. 调用useRef(初值),得到引用对象
// 3. 把引用对象设置ref 给任意的组件/元素
// 4. 通过引用对象.current 获取 组件/元素
const refTxt = useRef(null)
console.log(refTxt)
const click = () => {
console.log(refTxt.current)
}
return <div>
useRef, <input ref={refTxt} />
<button onClick={click}>点击,获取input中的值</button>
</div>
};
export default Func
7.场景,定时器
使用useEffect开启定时器会导致每次变化都开启一个新定时器,过度浪费性能,使用useRef则不同
import React,{useEffect,useState,useRef} from 'react'
const Func = () => {
const [count,setCount]=useState(5)
const [flag,setFlag]=useState(false)
const timeCount=useRef(null)
const btn=()=>{
setFlag(true)
timeCount.current=setInterval(()=>{
setCount((count)=>{
return count-1
})
},1000)
}
// 清除
useEffect(()=>{
if(count===0){
clearInterval(timeCount.current)
}
},[count])
return <div>
<button ref={timeCount} disabled={flag} onClick={btn}>按钮</button>
==={count}
</div>
};
export default Func
使用自定义hooks拆分
import React,{useEffect,useState,useRef} from 'react'
const useTime = () => {
const [count,setCount]=useState(5)
const [flag,setFlag]=useState(false)
const timeCount=useRef(null)
const btn=()=>{
setFlag(true)
timeCount.current=setInterval(()=>{
setCount((count)=>{
return count-1
})
},1000)
}
// 清除
useEffect(()=>{
if(count===0){
clearInterval(timeCount.current)
setFlag(false)
}
},[count])
return { count,btn,flag }
};
export default useTime
import React from 'react'
import useTime from './chaifen';
const Func = () => {
const { count,btn,flag}=useTime()
return <div>
<button disabled={flag} onClick={btn}>按钮</button>=={count}
</div>
};
export default Func
六 useContext
1.是什么
全局状态,类似于后代传参
3.怎么用
- 导入并调用createContext方法,得到Context对象,导出
- 使用 Provider 组件包裹根组件,并通过 value 属性提供要共享的数据
- 在任意后代组件中,如果希望获取公共数据:导入useContext;调用useContext(第一步中导出的context) 得到value的值
实例
父
import React,{useState,createContext} from 'react'
import Son from './son'
export const Context = createContext()
const Func = () => {
const [color,setColor]=useState('red')
return (
<Context.Provider value={ color }>
<div>
<button onClick={()=>setColor('green')}>按钮</button>
<Son></Son>
</div>
</Context.Provider>
)
};
export default Func
子
import React, { useContext } from 'react'
import { Context } from './App'
const CC = () => {
const colo = useContext(Context)
return ( <div>=son=={colo} </div>)
}
export default CC