react 面试markdown 自用

React 面试

1. 什么是HOC高阶组件

比如 react-redux 中的 connect 组件,接受一个组件,返回一个新的组件,给新的组件添加新的组件
缺点 : 容易形成嵌套地狱
现在主要用hook 使用状态

2. 函数/类 组件中如何使用state

组件内部state,适合在本组件使用。有点灵活,缺点难以实现组件共享
函数组件 用useState useReducer
类组件 this.state 修改this.setState
组件外的state ,用状态管理库。redux dva umi

3. redux 原理

修改状态,使用subscribe订阅刷新页面,后有了hook,usedDispatch之类的hook
将订阅页面更新放到了页面里面
redux 中的subscribe返回值是取消订阅 (想想源码的return

4. 常见组件性能优化手段

4-1. 复用组件

复用的前提必须满足三个条件:同一层级下,同一类型,同一个key值,所以我们尽量保证这三者的稳定性

常见错误比如key=Match.random() 做key值 这样就会每次卸载旧的组件 生成新的组件
不规范写法 用key = index 但是组件如果发生拖拽啥的就寄了

4-2. 尽量减少组件的重新render

  1. 在类组件中 通过shouldcomponentupdate生命周期判断
    this.props.item !==nextPpropsitem 就return false 不更新

  2. 类组件中 使用purcomponent 内置了通过shouldcomponentupdate,通过判断props是否有变化

  3. 函数组件中 使用memo 其实HOC高阶组件,memo会检查属性是否发生变化,来选择是否重新渲染,源码会进行浅比较会直接进入bailout,也可以自定义函数,放进去一个callback函数

            const a = memo(function Home() {
                return(<>
                    home page
                </>)
            },(pre,current)=>{
                return pre.item !== current.item
            })
    
  4. useMemo 把返回值返回到filber节点上

    export default const a =({item}) =>{ //这里child组件并不依赖item的变化重新更新
        return useMemo (() => {
            <div>
                {item}
                <Child/>
            </div>
        })
    }
  1. useCallback 可以缓存函数
    使用useCallback(fn,deep) == useMemp (() => fn,deep)

  2. context value 只要发生变化 消费这个组件的后代consumer都要更新 所以要尽量的精简实用 比如项目里页面初次加载就把所有的dymanic数据和static数据全请求出来
    比如拆分不想管的context 比如俩个不想关联的context 拆开 这样就不用修改某个的时候 全部渲染了

5. hook解决了什么问题

  1. 组件之间状态难以复用,比如最早的redux ,如果想用store里面的值,只能每个组件页面进来订阅,页面销毁取消订阅。最好的方式就是些一个HOC高阶组件,让所有组件进来就订阅, 但是也会形成
    嵌套地狱,后面几个括号,不方便阅读
    有了hook之后就是一个自定义hook,函数组件之间的状态服用,直接useSelector
  2. 复杂组件难以理解
    一个生命周期里写了好几个组件的逻辑,臃肿,hook 可以写几个副作用,方便阅读,甚至可以写自定义hook
  3. 类组件的this

6. 什么是自定义hook

就是自己封装的hook 最经典的就是alibaba/ahooks 里面的一些定时器,forceupdate

7,为什么hook出现之后 就可以定义state了 或者说为什么之前函数组件不能有自己的状态

之前函数组件不能保存状态是因为当状态改变的时候 页面就要重新渲染 这样定义在函数里面的变量就会重新生成复制,肯定不行,如果定义在函数外面全局污染 直接傻杯
所以hook出现后 封装了useState 和 useReducer方法 把state状态保存到了filber上

8. useState 和 useReducer

简单的用state 复杂想复用的用useReducer
注意 state 不改变页面不刷新  reducer 刷新

9. 为什么useState 和 useReducer 返回的是数组 不是其他的结构

因为如果肯定要有一个状态 ,和改变状态的俩个变量,如果是对象解构的话就名字定死了,数组就可以随便起名字了

10. useEffect/ useLayoutEffect 用法区别

首先回顾一下什么是副作用,改变dom ,添加订阅,设置定时器,记录日志等等

简单的例子 – 比如说一个ajax 就要写到effect 里面 直接写到函数体里 每次都执行 而且可能阻塞后面js的运行

怎么选?
大部分场景都用useEffect ,那useEffect 和 useLayoutEffect有什么区别
通过掘金老哥和自己查的资料这么理解:
首先uselayoutEffect是同步,useEffect是异步
useEffect是组件渲染在页面渲染后延迟执行,而usLayoutEffect是在所有的dom变更之后执行

掘金老哥的例子
使用useEffect 这里会闪烁 ,setcount 会先让count值变为0,然后useEffect会让count更改为一个随机数,因为很快,所以会闪烁

function App() {
  const [count, setCount] = useState(0);
  
  useEffect(() => {
    if (count === 0) {
      const randomNum = 10 + Math.random()*200
      setCount(10 + Math.random()*200);
    }
  }, [count]);

  return (
      <div onClick={() => setCount(0)}>{count}</div>
  );
}



使用useLayoutEffect不回闪烁,layout要等里面的签名函数全部执行完后,才更新刷新渲染,这个时候时候count的值已经是随机数了
用户感知不到count是0这一个变化,也就是说这里layout和setcount是同时执行的,而上面的uerEffect是setCount已经重新渲染页面了,然后才执行签名函数里面的set为随机数

function App() {
  const [count, setCount] = useState(0);
  
  useLayoutEffect(() => {
    if (count === 0) {
      const randomNum = 10 + Math.random()*200
      setCount(10 + Math.random()*200);
    }
  }, [count]);

  return (
      <div onClick={() => setCount(0)}>{count}</div>
  );
}

再总结一下,就是effect会先渲染页面,然后执行里面的签名函数,而useLayoutEffect不会等页面渲染完才执行,同时执行,也就是所谓的同步异步,然后可以举这个例子,setcount 外面执行一次,副作用函数里面执行一次

再比如 ract-router-dom v6里面 就使用用useLayoutEffect 因为要去监听,history 。如果用effect的话,就是该更新了(setstate了),但是还没监听呢

柯利化

记住这个柯利化

function addware(...arg) {
    return (params) => (arg1) => {
        console.log('ageOutSide',arg)
        console.log('inside1', arg1)
        console.log('inside2', params)

    }
}
const useEnhancer = (enhancer) => {
    return  enhancer('params1')('params2')
}
addware('addwareparams')

useEnhancer(addware('addwareparams'))

你可能感兴趣的:(react.js,前端,javascript)