函数式组件
rfc
- 函数式组件的this为
undefined
,因为babel开启了严格模式 - render执行:解析组件标签,发现是函数定义,随后调用该函数,将虚拟DOM转为真实DOM
- 函数就相当于
render
,会调用n+1
次 - 再没有hooks之前,函数只能通过首个参数接收props,state,生命周期,ref都不行
useState(state状态)
声明
-
采用数组解构,第一个为state属性,第二个为更改state的方法(setState)
let [num, setNum] = useState(0)
使用
同样有两种写法,但多次调用最后都会合并
-
对象式
setNum(num + 1)
-
函数式:参数为当前state
setNum((num) => num + 1)
-
useState()参数为初始值,并会作为缓存,所以不会随着 render 而调用
useEffect(生命周期)
useEffect(callback,[])//监听更新的名单
-
参数:
- 如果没值,则为初始化+监听所有,callback相当于 componentDidMount + componentDidUpdate
- 如果为
[]
,则为初始化,callback相当于componentDidMount - 如果
[]
里有值,则为初始化+监听指定值的更新
-
模拟componentWillUnmount:callback内再 return 一个 callback
useEffect(() => { let timer = setInterval(() => { setNum(num+1) }, 500); return () => { clearInterval(timer) } }, [num])
useRef
- 和类组件
createRef
用法相似
import React, {useRef } from 'react'
export default () => {
let input1=useRef()
let show=()=>{
console.log(input1.current.value);
}
return (
<>
<input ref={input1} onChange={show} type="text" />
</>
)
}
Fragment
-
Fragment不会被渲染(类似vue的template)
//简写 <> </>
-
Fragment只能接受key,并不能简写
<Fragment key={}> </Fragment>
useReducer
const initialState = {count: 0};
function reducer(state, action) {
switch (action.type) {
case 'increment':
return {count: state.count + 1};
case 'decrement':
return {count: state.count - 1};
default:
throw new Error();
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<>
Count: {state.count}
<button onClick={() => dispatch({type: 'decrement'})}>-</button>
<button onClick={() => dispatch({type: 'increment'})}>+</button>
</>
);
}
useMemo
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
- 参数触发机制同useEffect
- 返回的值不受响应式影响
- 返回callback返回的值,并优先读取缓存
- 使用场景:函数式组件没有getSnapshotBeforeUpdate生命周期钩子,存在性能问题(同类组件的React.Component性能问题)
export default function WithoutMemo() {
const [count, setCount] = useState(1);
const [val, setValue] = useState('');
function expensive() {
let sum = 0;
for (let i = 0; i < count * 100; i++) {
sum += i;
}
return sum;
}
return <div>
<h4>{count}-{val}-{expensive()}</h4>
//无论是修改count还是val,都会触发expensive的执行
<div>
<button onClick={() => setCount(count + 1)}>+c1</button>
<input value={val} onChange={event => setValue(event.target.value)}/>
</div>
</div>;
//使用useMomo
export default function WithMemo() {
const [count, setCount] = useState(1);
const [val, setValue] = useState('');
const expensive = useMemo(() => {
console.log('compute');
let sum = 0;
for (let i = 0; i < count * 100; i++) {
sum += i;
}
return sum;
}, [count]);
return <div>
<h4>{count}-{expensive}</h4>
{val}
<div>
<button onClick={() => setCount(count + 1)}>+c1</button>
<input value={val} onChange={event => setValue(event.target.value)}/>
</div>
</div>;
}
useCallback
- 和useMemo类似,只不过其返回的是优先缓存的函数
- 使用场景:父子组件的性能优化
import React, { useState, useCallback, useEffect } from 'react';
function Parent() {
const [count, setCount] = useState(1);
const [val, setVal] = useState('');
const callback = useCallback(() => {
return count;
}, [count]);
return <div>
<h4>{count}</h4>
<Child callback={callback}/>
<div>
<button onClick={() => setCount(count + 1)}>+</button>
<input value={val} onChange={event => setVal(event.target.value)}/>
</div>
</div>;
}
function Child({ callback }) {
const [count, setCount] = useState(() => callback());
useEffect(() => {
setCount(callback());
}, [callback]);
return <div>
{count}
</div>
}