React

96 阅读3分钟

生命周期

juejin.cn/post/709613…

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

相当于 componentDidMountcomponentDidUpdate 和 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
  • 组件懒加载