3

1,说说react里面bind函数与箭头函数

bind 由于在类中,采用的是严格模式,所以事件回调的时候会丢失this指向,指向的undefined,需要使用bind来给函数绑定上当前实例的this指向。

箭头函数的this指向上下文,所以永久能拿到当前组件实例的。this指向我们可以完美的使用箭头函数来替代传统事件处理函数的回调。

2,说出几点React中的性能优化

  • 使用shouldComponentUpdate来对state和props进行对比,如果两次的结果一样,那么就return false;
  • 使用纯函数组件pureComponent;

3,简单解释下高阶组件和高阶函数

  • 高阶函数,指的是函数接收一个函数作为参数,或者将函数作为返回值的函数就是高阶函数 。
  • 高阶组价,接受一个组件,并返回一个新组建的组件就是高阶组件,本质上和高阶函数的意思一样的,高阶组件是用来复用react代码的一种方式。

4,setState和repalceState有什么区别

  • setState 是修改其中的部分状态,相当于 Object. assign,只是覆盖,不会减少原来的状态。
  • replaceState 是完全替换原来的状态,相当于赋值,将原来的 state 替换为另一个对象,如果新状态属性减少,那么 state 中就没有这个状态了。

5,Redux中核心组件有哪些,reducer的作用

Redux由Action、Reducer和Store三部分构成,他们的解释如下:

  • action:action理解为动作,action的值一般为一个对象,格式如 { type: "", data: "" },type是必须要的,因为reducer处理数据的时候要根据不同的type来进行不同的操作。
  • reducer:reducer是初始化以及处理派发的action的纯函数。
  • store:store是一个仓库,用来存储数据,它可以获取数据,也可以派发数据,还能监听到数据的变化。

而reducer的作用就是接收旧的 state 和 action,返回新的 state。

6,什么是受控组件

受控组件就是可以被 react 状态控制的组件。在 react 中,Input textarea 等组件默认是非受控组件(输入框内部的值是用户控制,和React无关)。但是也可以转化成受控组件,就是通过 onChange 事件获取当前输入内容,将当前输入内容作为 value 传入,此时就成为受控组件。

7,hooks+context和redux你是怎么选择的,都在什么场景下使用

如果项目体量较小,只是需要一个公共的store存储state,而不讲究使用action来管理state,那context完全可以胜任。反之,则是redux的使用场景。

在进行状态管理时,通常遵循以下的原则:

  • 如果你在组件间传递的数据逻辑比较复杂,可以使用redux;
  • 如果组件层级不多,可以使用props;
  • 如果层级较深,数据逻辑简单,可以使用context。

8,使用useffect 模拟生命周期

  • 模拟componentDidMount。第二个参数为一个空数组,可以模拟componentDidMount,示例如下。
componentDidMount:useEffect(()=>{console.log('第一次渲染时调用')},[]) 
  • 模拟componentDidUpdate。没有第二个参数代表监听所有的属性更新,示例如下。
useEffect(()=>{console.log('任意状态改变')})  

如果需要监听多个属性的变化则需要将属性作为数组传入第二个参数。

useEffect(()=>{console.log('指定状态改变')},[状态1,状态2...])  
  • 模拟componentWillUnmount
useEffect(()=>{   ...  return()=>{ //组件卸载前}   }) 

9,setsate和usestate的区别

  • setState( updater [,callback] ):构造函数是唯一建议给 this.state 赋值的地方,不建议直接修改 state 的值,因为这样不会重新渲染组件,自动进行浅合并(只会合并第1层),由于 setState() 异步更新的缘故,依赖 state 旧值更新 state 的时候建议采用传入函数的方式。
  • useState(initState):setState(updater) 用于修改状态的方法,updater:object/function 用于更新数据,initState用于状态的初始值。

10,如何监听react父组件props变化。

当props发生变化时执行,初始化render时不执行,在这个回调函数里面,你可以根据属性的变化,通过调用this.setState()来更新你的组件状态,旧的属性还是可以通过this.props来获取,这里调用更新状态是安全的,并不会触发额外的render调用。

componentWillReceiveProps(props) { 
        console.log(props) 
    this.setState({show: props.checked}) 
} 

11,usememo的作用,以及怎么使用

返回一个 memoized 值。

把“创建”函数和依赖项数组作为参数传入 useMemo,它仅会在某个依赖项改变时才重新计算 memoized 值。这种优化有助于避免在每次渲染时都进行高开销的计算。传入 useMemo 的函数会在渲染期间执行。请不要在这个函数内部执行与渲染无关的操作,诸如副作用这类的操作属于 useEffect 的适用范畴,而不是 useMemo。

如果没有提供依赖项数组,useMemo 在每次渲染时都会计算新的值。

你可以把 useMemo 作为性能优化的手段,但不要把它当成语义上的保证。将来,React 可能会选择“遗忘”以前的一些 memoized 值,并在下次渲染时重新计算它们,比如为离屏组件释放内存。先编写在没有 useMemo 的情况下也可以执行的代码 —— 之后再在你的代码中添加 useMemo,以达到优化性能的目的。

12,React的Component和Purecomponent区别

Component 没有直接实现 shouldComponentUpdate 这个方法,但是 PureComponent通过浅层的Porps 和 state 的对比,内部实现了这个生命周期函数。

PureComponent会跳过整个组件子树的props更新,要确保全部的子组件也是 pure 的形式。

Component 中需要手动执行的 shouldComponentUpdate 函数,在PureComponent中已经自动完成了(自动浅对比)。

PureComponent不仅会影响本身,而且会影响子组件,所以PureComponent最好用在数据展示组件中。

PureCoponent 如果是复杂数据类型,这里会造成错误的显示(setState浅复制更新,但是界面不会重新渲染)。

13,Hooks相对于类有哪些优化

首先,我们来看一下类组件的一些缺点:

缺点1:复杂且不容易理解的“this”。

Hooks解决方式:函数组件和普通JS函数非常相似,在普通JS函数中定义的变量、方法都可以不使用“this.”,而直接使用该变量或函数,因此你不再需要去关心“this”了。

缺点2:组件数据状态逻辑不能重用

Hooks解决方式:通过自定义Hook,可以数据状态逻辑从组件中抽离出去,这样同一个Hook可以被多个组件使用,解决组件数据状态逻辑并不能重用的问题。

缺点3:组件之间传值过程复杂

Hooks解决方式:通过React内置的useState()函数,可以将不同数据分别从"this.state"中独立拆分出去。降低数据复杂度和可维护性,同时解决类组件缺点三中“内部state数据只能是整体,无法被拆分更细”的问题。

通过React内置的useEffect()函数,将componentDidMount、componentDidUpdate、componentWillUncount 3个生命周期函数通过Hook(钩子)关联成1个处理函数,解决事件订阅分散在多个生命周期函数的问题。

14,Hooks父组件怎么调用子组件的方法

父组件使用 useRef 创建一个 ref 传入 子组件 子组件需要使用。useImperativeHandle 暴露 ref 自定义的实例值给父组件,并且需要使用 forwardRef 包裹着。

15,React通过什么方法修改参数?

类组件修改数据的方法, 通过setState , 注意setState的修改方法有两种,而且它是异步的

函数组件修改方式通过自定义的方法。需要通过 useState , 例如。const [count,setCount] = useState(0)。

16,说说你对react native的了解

React native 基于 JavaScript 开发的一个 可以开发原生app的这么一个集成框架,它兼容开发 iOS 和 Android能够实现一套代码,两个系统都能使用,方便维护,相比于web前端的 react ,react-native更好的提供了一些调用手机硬件的API,可以更好的开发移动端,现在react-native它的生态环境也是越来越好,基本上可以完全实现原生开发,

但是现在好多的应用还是用它来套壳 (原生 + web前端),用它来做有些路由,和框架的搭建,然后里面内容来使用前端的react来实现,这样一来让维护更方便,开发更快捷

17,React的输入框输入文字就会触发onchange,怎么拿到他最后输入的结果呢?

方法1:通过受控组件,可以获取到state里面的值,获取修改结果,代码如下。

 class Home extends React.Component { 
    state = { 
        val:"" 
     } 
     //这是一个通用的写法,然后注意 name的值一定要与state定义的一直 
    changeInput = (e) =>{ 
        let {name,value} = e.target 
        this.setState({ 
           [name]:value 
       }) 
    } 
    render(){ 
       return <> 
         <input onChange="this.state.val" /> 
       </> 
    } 
 } 

方法2:通过ref来获取里面的值。

class Home extends React.Component { 
  render(){ 
      //this.val 获取里面的真是dom 
      return <input ref={node=>this.val} /> 
   } 
} 

18,React的render什么时候渲染

React生命周期有三个阶段。 两个阶段都会执行 render 主要从更新和挂载两个阶段来讲,挂载阶段会执行一次,更新阶段主要会涉及shouldComponentUpdate。

首先,我们看一下挂载阶段:

constructor(){} 
static getDerivedStateFromProps(){ 
   return {} 
 } 
 
render(){}  //挂载阶段会执行一次 
componentDidMount(){} 

接下来,我们看一下更新阶段:

static getDerivedStateFromProps(props, state){rerturn {}} 
shouldComponentUpdate(nextProps, nextState).{ 
     return Boolean  //注意如果 false 则 不向下执行 ,true的时候会执行render
} 


render() ..       

19,useEffect的依赖为引用类型如何处理

useEffect的依赖为引用类型的时候,可能会导致监听不出发,原因就是监听的统一个地址的时候,对象本身地址没变,所以监听的结果就是认为数据并没有改变从而不直接调用。

解决的方法有以下几点:

  • 如果数据是对象的话,可以监听对象的里面的值,值是基本类型,如果值改变了,那么可以监听执行;
  • 在去修改对象和数据的时候,使用参拷贝或者浅拷贝,这样地址发生改变可以监听执行;
  • 可以转成字符串,通过JSON.stringify() ,监听字符串这样的,这样改变也会执行;

20,说一下 key发生哪些变化会触发什么生命周期

React的key值给组件作为唯一标识,类似身份证,当数组发生增删改查的时候可以通过这个 标识来去对比虚拟dom的更改前后,如果相同标识的数据或者属性没有改变的话,讲直接略过,对比有改变的然后直接改变此项。

如果给组件添加key,如果key值改变的时候,组件将会触发如下的生命周期:

  • constructor
  • getDerivedStateFromProps()
  • render(){}
  • componentDidUpdate

21,说说React里面的createPortal。

react.createPortal() 这个方法是来使用做弹窗Modal组件的,在没有这个组件之前我们可以自己定义组件,然后去实现Modal效果。

const styles = { 
  modal: { 
    position: 'fixed', 
    top: 0, 
    left: 0, 
    right: 0, 
    bottom: 0, 
    backgroundColor: 'rgba(0,0,0,0.3)', 
    display: 'flex', 
    justifyContent: 'center', 
    alignItems: 'center' 
  } 
} 
 
class Modal extends Component { 
  constructor(props) { 
    super(props); 
  } 
  render() { 
    return ( 
      <div style={styles.modal}> 
        {this.props.children} 
      </div> 
    ); 
  } 
} 

react.createPortal 这个来制作弹窗组件,它 在Modal 组件位置进行 fixed 定位,可以任意的挂载到某个dom元素上,使用后的管理更方便,但是注意需要预留html的挂载元素。

22,说一下React全家桶

真正意义上的react全家桶,其实指的是react,react-dom,react-native。因为react核心库只是vDom的操作,无关dom(dom操作在react-dom中)——这意味着它天生就可以做到跨平台。

注意这里有误区,react-router,react-router-dom,react-dux只是社区的一些使用较多的解决方案,事实上它们各有缺陷。

23,简单介绍下fiber

React Fiber 是 React 框架的一种底层架构,为了改进 React 的渲染引擎,使其更加高效、灵活和可扩展而提供的。

传统上,React 使用一种称为堆栈调和递归算法来处理虚拟 DOM 的更新,这种方法在大型应用或者频繁更新的情况下可能会产生性能问题。React Fiber 则是基于一种增量渲染的思想,它将更新任务分解成小的、可中断的单元,使得 React 在更新时可以更灵活地控制和切换任务,提高应用的响应性。

React Fiber 的核心功能包括:

  • 增量渲染: React Fiber 将更新任务拆分成多个小任务单元(称为 “fiber”),并使用优先级调度器来处理这些任务,以提高响应性和用户体验。
  • 优先级调度: Fiber 引入了优先级概念,使 React 能够根据任务的优先级来决定任务的执行顺序,确保高优先级任务得到及时处理。
  • 中断与恢复: React Fiber 允许在渲染过程中中断任务,然后在适当的时机恢复执行,从而避免了阻塞的情况。
  • 任务取消: Fiber 具备任务取消的能力,可以取消不必要的更新,提高性能。

24,谈谈你对Hooks的理解

react-hooks提供给了函数式组件以业务逻辑抽离封装的能力,从单一组件单位进行UI与业务逻辑的分离,以此来保证函数式组件的UI纯净。

Hooks的出现解决了两个问题:

  • 组件的状态逻辑复用
  • class组件自身的问题

组件的逻辑复用:在hooks出现之前,react先后尝试了 mixins混入,HOC高阶组件,render-props等模式但是都有各自的问题,比如mixin的数据来源不清晰,高阶组件的嵌套问题等等

Class组件自身的问题:class组件本身提供了很多东西,有不可忽视的学习成本,比如各种生命周期,this指向问题等等。

25,什么是副作用,聊聊useEffect的副作用,以及如何解决

副作用函数

我们将跟UI渲染无关的业务逻辑称之为副作用。

useEffect是react在函数式组件里提供的副作用解决方案,它接受两个参数。第一个是必传参数,类型为函数。我们写在此函数中的业务逻辑代码就是我们所说的副作用。

消除副作用

默认情况下,useEffct会在每次render后执行传入的副作用函数。然而有的时候我们需要在执行副作用前先去除掉上次render添加的副作用效果,我们可以在副作用函数里再返回一个函数,这个函数就是消除副作用,它会在每次reRender前和组件卸载时去执行。

监听器

与 useMemo, useCallback等一样,useEffect可以传入一个监听数组参数,这意味着副作用只有在数组中的监听值变化时才会执行。借助它的这个参数特性,可以模拟类组件生命周期钩子,比如componentDidMount等。


xiangzhihong
5.9k 声望15.3k 粉丝

著有《React Native移动开发实战》1,2,3、《Kotlin入门与实战》《Weex跨平台开发实战》、《Flutter跨平台开发与实战》1,2和《Android应用开发实战》