zh-hans.reactjs.org/docs/hooks-…Hook API 索引
useSelector
react-redux@7 的 useSelector API . 用来获取redux里抛出的redux变量
import {useSelector} from 'react-redux';
//组件里
const state = useSelector(state => {
return {
chatBadgeCount: state.chat.chatBadgeCount,
letterBadgeCount: state.sideMenu.letterBadgeCount,
};
});
//使用
<MsgBubbleCom
wd={px2dp(18)}
hg={px2dp(18)}
account={state[item.markKey]}
color={'white'}
/>
useMemo/useCallback
memo是用来优化函数组件的重渲染问题,当传入的属性值都没变化时就不会触发组件的重渲染,否则组件就会重渲染. (传入子组件的值没有变化时,不让子组件渲染, 包裹组件 )
当父组件引入子组件的情况下,往往会造成组件之间的一些不必要的浪费.
const Count = memo(function Count(props) {
console.log('count render')
return <div>子组件count值:{props.double}</div>
})
//只有double改变的时候,才会重新渲染组件
<Count double={double} />
useMemo功能是判断组件中的函数逻辑是否重新执行,用来优化性能。
(子组件依赖几个值,值变了,子组件也变化, 包裹函数 )
useMemo的用法与useEffect非常相似,如果第二个参数为空则函数组件每次被渲染,useMemo内的逻辑都会被执行。如果第二个参数为一个空数组,那么仅会在组件第一次被渲染时执行。其他的情况都是在数组内元素完全相同时才不执行
const [count, setCount] = useState(0);
//第一个参数是要执行的函数
//第二个参数是执行函数依赖的变量组成的数据
//这里只有count发生变化double才会重新计算
const double = useMemo(() => {
return count * 2;
}, [count])
<Count double={double} />
const container = React.useMemo(() => {
return (
<Animated.View
style={[
styles.container,
styles.center,
{
height: barHeight,
},
]}>
{toolsIcon}
</Animated.View>
);
}, [barHeight, toolsIcon]);
useCallback
useMome、useCallback用法都差不多,都会在第一次渲染的时候执行,之后会在其依赖的变量发生改变时再次执行,并且这两个hooks都返回缓存的值,useMemo返回缓存的变量,useCallback返回缓存的函数。
const value = useMemo(fnM, [a]);
const fnA = useCallback(fnB, [a]);
//参数为[]
父级调用子级时,在onClick参数上加上useCallback,参数为[],则第一次初始化结束后,不在改变。
<ChildMemo name={name} onClick={ useCallback((newName: string) => setName(newName), []) }/>
在子组件不需要父组件的值和函数的情况下,只需要使用memo函数包裹子组件即可。而在使用函数的情况,需要考虑有没有函数传递给子组件使用useCallback。而在值有所依赖的项,并且是对象和数组等值的时候而使用useMemo(当返回的是原始数据类型如字符串、数字、布尔值,就不要使用useMemo了)。不要盲目使用这些hooks。
hooks暴露方法属性给父级
//------------ 父级 ------------
renderToolBar(){
//获取ref的实例
return <ToolBarCom ref={ref => (this.ToolBarRef = ref)} />;
}
//调用
_onScroll(event) {
this.ToolBarRef && this.ToolBarRef.scrollEvent(event);
this.changeActivityIcon();
}
//------------ 子级 ------------
//hook暴露这个组件的ref给父级
//1.传入ref
const ToolBarCom = (props, ref) => {
//2.暴露属性给父级
useImperativeHandle(ref, () => ({//第一个参数:暴露哪个ref;第二个参数:暴露什么
openPullAni: flag => {
onRefresh();
},
value: inputEl.current.value, //属性
scrollEvent: animEvent,
}));
//3.通过forwardRef把组件当作ref传出
export default React.forwardRef(ToolBarCom);
useRef
useRef 返回一个可变的ref对象,其.current属性被初始化为传入的参数(initialValue)。返回的 ref 对象在组件的整个生命周期内保持不变。
function TextInputWithFocusButton() {
const inputEl: MutableRefObject<any> = useRef(null);
const onButtonClick = () => {
// `current` 指向已挂载到 DOM 上的文本输入元素
inputEl.current.focus();
};
return (
<>
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>Focus the input</button>
</>
);
}
在组件的整个生命周期里,inputEl.current都是存在的,这扩展了useRef本身的用途,可以使用useRef维护类似于class.component中实例属性的变量。
利用ref保存前一个值.
发生了什么:
//setCount方法调用, 触发userEffect[count], 这个时候给preCount给旧值.
//useRef相当于被初始化为传入的参数(initialValue),不调用 prevCountRef.current =,值不会变.
const Count = () => {
const [count, setCount] = useState(0);
const prevCountRef = useRef(count);
const prevCount = prevCountRef.current;
useEffect(() =>{
//在setCount执行完成前触发,拿到之前的值
prevCountRef.current = count;
console.log('useEffect:', prevCountRef)
}, [count]);
return (
<div>
<button onClick={() => { setCount( count + 1 ) }}>加1</button>
<p>count: {count}</p>
<p>prevCount: {prevCount}</p>
</div>
)
}
利用ref保存未来的值
function Example() {
const [count, setCount] = useState(0);
const currentCount = useRef(count);
// currentCount.current现在是旧值,因为新值还没有给进去
const prevCount = currentCount.current;
//count挂载的useState,最新的值.
currentCount.current = count;
return (
<div>
<p>prev: {prevCount}</p>
<p>current: {currentCount.current}</p>
<button onClick={() => setCount(count + 1)}>setCount</button>
</div>
);
}
export default Example;
forwardRef
forwardRef,它是react16新增的方法,返回react组件。
import React,{Component} from 'react';
import ReactDOM,{render} from 'react-dom';
const Child = React.forwardRef((props,ref)=>{
return (
<div ref={ref}>{props.txt}</div>
)
})
class Parent extends Component{
constructor(){
super();
this.myChild = React.createRef();
}
componentDidMount(){
console.log(this.myChild.current);//获取的是Child组件中的div元素
}
render(){
return <Child ref={this.myChild} txt="parent props txt"/>
}
项目里的例子
//父级
const pullRef = useRef();
pullRef.current.deleteItem(index);
/**
* 渲染整体列表
* @method _renderList
* @return {any}
*/
const _renderList = (() => {
return <PullListCom
ref={pullRef}
renderItem={renderItem}
onFetch={_onFetch}
emptyTip={emptyTip}
emptyHeight={158}
networkStatus={networkStatus}
/>;
})();
//子级
export default forwardRef(PullListCom);