useReducer
- 规定了数据是单向流动的
- 数据存储在数据仓库中(可以认为数据就是当前组件内的state)
- action是改变数据的唯一原因(本质上就是一个对象,action有两个属性)
- type:string 规定动作的类型
- payload:any 动作发生后的附加信息
- 具体改变数据的是一个函数,该函数叫做reduce(纯函数,不能有副作用),该函数必须
返回结果
,用于表示数据仓库变化之后的数据(Flux要求,对象是不可变的,如果返回对象,必须创建新的对象
),该函数不可直接调用,必须借助dispatch
触发,该函数接收两个参数
- state:数据仓库中的数据
- action: 描述了如何改变数据
使用
import { useReducer } from 'react
/***
* reducer reducer函数
* initState 初始状态
* fn 接收一个参数,是initState,返回一个状态,此状态会覆盖initState
/
const [state, dispath] = useReducerr(reducer, initState, fn);
useReducer实现过程
export default function useReducer(reducer, initState,fn) {
const [state, setState] = useState(fn ? fn(initState) : initState);
function dispath(action) {
const newState = reducer(state, action);
conole.log(`变量值${state}-->${newState}`);
setState(newState);
}
return [state, dispath];
}
useContext
用于获取上下文数据,减少组件嵌套
import React from 'react'
const ctx = React.createContext();
// 方法一
function Test() {
return <ctx.Consumer>
{value => <div>上下文的值:{value}</div>}
</ctx.Consumer>
}
// 方法二
function Test() {
const value = useContext(ctx);
return <div>上下文的值:{value}</div>
}
export default function App() {
return (
<ctx.Provider value="test">
<Test />
</ctx.Provider>
)
}
useCallback
用于得到一个固定引用值的函数,通常用来做性能优化
该函数有两个参数:
- 函数,useCallback会固定该函数的引用,只要依赖项没有发生变化,则始终返回之前函数的地址
- 数组,记录依赖项
// 纯组件会进行浅比较,如果值一致不应该发生渲染
class Son extends React.PureComponent {
render() {
return <div>
<div>{this.props.text}</div>
<button onClick={this.props.onClick}>改变文本</button>
</div>
}
}
function Parent() {
const [n, setN] = useState(0);
const [val, setVal] = useState('');
// 方法一
const handleClick = () => {
setN(Math.random());
};
// 方法二
const handleClick = useCallback(() => {
setN(Math.random());
}, []);
return (
<div>
// 函数地址每次渲染都发生了变化,导致子组件重新渲染,若子组件是经优化过的组件,则可能导致优化失效
<Son text={n} onClick={handleClick} />
<input type="number"
value={n}
onChange=(e => setN(e.target.value))
/>
</div>
)
}
function App() {
return (
<div>
<Parent />
</div>
)
}
每次执行setN,状态变化时,方法一都会返回一个新的函数引用;方法二只要依赖项不发生变化,都会返回之前的函数引用。
useMemo
用于保持一些比较稳定的数据,一般用于高开销的性能场景,做性能优化
// 和useCallbakc使用区别,useCallback返回函数本身,useMemo返回新函数
const handleClick = useMemo(() => {
return () => {
setN(Math.random());
}
}, []);
// 比如渲染10000个数,只要依赖项不发生变化,其他状态的改变不应该影响这个组件的渲染
const list = useMemo(() => {
const list = [];
for(let i = 0; i < 10000; i++) {
list.push(<Item key={i} value={i} />)
}
return list;
}, []);
useLayoutEffect
时间点: 操作DOM--->(componentDidMount、componentDidUpdate、useLayoutEffect) ---> 用户看到新的效果 ---> useEffect
- useEffect: 浏览器渲染完成后,用户看到新的渲染结果之后(会先渲染完毕再操作,不会一直白屏卡住)
- useLayoutEffect: 完成了DOM改动,还没呈现给用户(相当于componentDidMount、componentDidUpdate)
尽量使用useEffect,因为他不会阻塞渲染,如果出现了问题,再考虑使用useLayoutEffect