生命周期
react事件处理机制
事件没有绑定在响应的dom上,在document用统一的事件处理程序来处理.利用事件冒泡
setState同异步情况
异步: 生命周期和合成事件中是异步
同步:其它情况是同步
通信
利用props,和子组件调用父组件的函数完成父子通信
利用redux
利用pubsub-js插件
受控组件
状态受react控制,表单元素的唯一数据源为state,在change事件时用setState去控制数据源
render props
相当于vue中的插槽技术
组件有个函数类型的prop属性
React.memo
React.memo()可接受2个参数,第一个参数为纯函数的组件;默认情况下其只会对复杂对象做浅层对比,如果你想要控制对比过程,那么请将自定义的比较函数通过第二个参数传入来实现。
仅检查 props 变更
PureComponent
PureComponent内部实现的shouldComponentUpdate方法只是对 state 和 props进行了浅比较,只是针对基本数据类型才有用,对于对象这种引用数据类型是不行的
hook
useState--状态hook
const [count, setCount] = useState(0);
元素1:属性
元素2:改变state属性的方法
useEffect
相当于 componentDidMount,componentDidUpdate 和 componentWillUnmount 这三个函数的组合.
useEffect(() => {
document.title = `You clicked ${count} times`;
return function cleanUp (){
// return cleanUp这个函数中的操作相当于在componentWillUnmount中的操作
clearInterval()
}
});
useEffect还可以设置参数二,来跳过 Effect
useEffect(() => {
document.title = `You clicked ${count} times`;
}, [count]); // 仅在 count 更改时更新
// 当参数二传一个空数组,可以让逻辑仅在挂载和卸载时执行
useLayoutEffect
useEffect 的函数会在组件渲染到屏幕之后执行
useLayoutEffect则是在DOM结构更新后、渲染前执行.useLayoutEffect里面的任务最好影响了Layout(布局)
但是,我们推荐你一开始先用 useEffect,只有当它出问题的时候(闪烁)再尝试使用 useLayoutEffect。
useContext
用于context中在孙组件中接收祖先组件传过来的内容
const value = useContext(MyContext);
useReducer
useState 的替代方案
const [state, dispatch] = useReducer(reducer, initialArg, init);
其中参数三为可选参数,作用是把初始 state 被设置为 init(initialArg)
function init(initialCount) {
return {count: initialCount}
}
function reducer(state, action) {
switch (action.type) {
case 'increment':
return {count: state.count + 1};
default:
throw new Error();
}
}
function Counter({initialCount}) {
const [state, dispatch] = useReducer(reducer, initialCount, init);
return (
<>
<button onClick={() => dispatch({type: 'increment'})}>+</button>
</>
);
}
useCallback--返回一个 缓存 的回调函数
useCallback(fn,deps)
- fn就是是一个函数,把你想要做的事放到函数中
- deps就是指fn函数所依赖的参数,如果没有依赖就可以不需要引入
useCallback结合着memo使用.memo给子组件套上,当子组件接受了一个函数类型的prop时(useCallback给函数用上).当父组件页面重新渲染,此时函数的地址不变,子组件也就不会重新渲染
useMemo--返回一个 缓存的值(类似于vue中的computed)
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
如果没有提供依赖项数组,useMemo 在每次渲染时都会计算新的值
useRef
- useRef可以用来定义变量,这些变量更改之后不会引起页面重新渲染
- 在DOM节点上定义ref属性,通过.current就可以获取到该DOM元素
- 更新 useRef 是 side effect (副作用),所以一般写在 useEffect 或 event handler 里
- ref 对象在组件的整个生命周期内保持不变
useImperativeHandle
可以让你在使用 ref 时自定义暴露给父组件的实例值
ref转发是用的同一个ref对象,但react官方不这么建议.
使用useImperativeHandle,可以让父、子组件分别有自己的 ref,通过 React.forwardRef 将父组件的 ref 透传过来,通过 useImperativeHandle 方法来自定义开放给父组件的 ref
const FancyInput = React.forwardRef((props, ref) => {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
}
}));
return <input ref={inputRef} type="text" />
});
const App = props => {
const fancyInputRef = useRef();
return (
<div>
<FancyInput ref={fancyInputRef} />
<button
onClick={() => fancyInputRef.current.focus()}
>父组件调用子组件的 focus</button>
</div>
)
}
redux hook
useSelector
获得状态
const yyy =useSelector(state => {
return state.xxx
});
useDispatch
获得diapatch方法
const diapatch=useDispatch()
// 这样就可以随意使用dispatch方法了
以上两个hook就代替了connect
性能优化
- 尽量使用函数组件
- 使用PureComponent或者React.memo
- 使用useMemo
- 组件懒加载