前端面试锦集之 react 万字长文面试总结

一、react 面试题
  1. redux 中间件的原理的理解,答案如下所示:
  • redux 是一个应用数据流框架,主要是解决了组件间状态共享的问题,原理是集中式管理,主要有三个核心方法,actionstorereducer
  • 工作流程是 view 调用 storedispatch 接收 action 传入 storereducer 进行 state 操作,view 通过 store 提供的 getState 获取最新的数据
  • 新增 state,对状态的管理更加明确,通过 redux,流程更加规范了,减少手动编码量,提高了编码效率,同时缺点时当数据更新时有时候组件不需要,但是也要重新绘制,有些影响效率。一般情况下,我们在构建多交互,多数据流的复杂项目应用时才会使用它们
  • 常用的一些 redux 中间件,如下所示:
    • redux-thunk:处理异步操作
    • redux-saga:处理异步操作
    • redux-promise:处理异步操作,actionCreator 的返回值是promise
  • 中间件的执行原理和koa中间件的执行原理类似,但是不是洋葱型的,而是半个洋葱,因为redux是单向执行的。当你应用了中间件,在触发一个action操作的时候,action操作就会经过先经过中间件,最终再形成dispatch(action)。一个触发一个action动作的时候,代码的执行逻辑。thunk是允许dispatch一个函数,而不是一个对象
  • thunk中间件的内部,代码如下所示:
function createThunkMiddleware(extraArgument) {

  return ({ dispatch, getState }) => next => action => {
    // 如果是函数,就执行函数
    if (typeof action === 'function') {
        return action(dispatch, getState, extraArgument);
    }
    // 如果不是,执行下一个中间件
    return next(action);
  };
}

const thunk = createThunkMiddleware();
thunk.withExtraArgument = createThunkMiddleware;

export default thunk;

  • 中间件的内部逻辑,代码如下所示:
const store = createStore(reducer, preloadedState, enchancer);

// 如果没有中间件,正常触发一个action;
// 如果有中间件的时候 creatStore内部的执行逻辑是这样的
// enchancer 就是你应用的中间件,调用applyMiddleware得到的组合中间件

function applyMiddleware(...middlewares) {
  return createStore => (...args) => {
  
    // 该创建的store还是要创建的,只传入了两个参数,没有中间件,得到的是正常的store
    const store = createStore(...args)
    let dispatch = () => {
      throw new Error(
        `Dispatching while constructing your middleware is not allowed. ` +
          `Other middleware would not be applied to this dispatch.`
      )
    }
    // 把getState、dispatch传给中间件
    const middlewareAPI = {
      getState: store.getState,
      dispatch: (...args) => dispatch(...args)
    }
    // 下面方法返回来了一个函数数组,中间件被剥离到
    // next => {}
    const chain = middlewares.map(middleware => middleware(middlewareAPI))
    // 再执行下面的,中间件就被剥离到
    // action => {}
    dispatch = compose(...chain)(store.dispatch)

    return {
      ...store,
      dispatch
    }
  }
}

// 下面得到的结果是 
// 假设中间件为 a b
// a(b(store.dispatch))
return enchancer(createStore)(reducer, preloadedState)// 结合上面thunk的源码{ dispatch, getState }) => next => action => {
    if (typeof action === 'function') {
        return action(dispatch, getState);
    }
    return next(action);
  };

  • 经过上面的操作后,经过中间件包装后的store的样子,假设中间件为 a b c,每一个中间件配发了一个原始storedispatch,中间件函数嵌套执行,如下所示
    • 没有中间件,代码如下
      store = {
          dispatch,
          ... ...,
          subscribe,
          getState
      }
      
      
    • 经过中间包装后,代码如下
      store = {
          dispatch: a(b((store.dispatch))),
          ... ...,
          subscribe,
          getState
      }
      
      
  • redux-thunk就是一个封装函数,允许store.dispatch一个函数,compsoe内部,如下所示:
// compose本身并不改变函数的执行,将函数组合后又返回了一个函数
    function compose(...funcs) {
      if (funcs.length === 0) {
        return arg => arg
      }
      if (funcs.length === 1) {
        return funcs[0]
      }
        return funcs.reduce((a, b) => (...args) => a(b(...args)))
    }

  1. 你会把数据统一放到 redux 中管理,还是共享数据放在 redux 中管理,答案如下所示:
  • 不是react native,所有数据都要放在redux中管理。如果只是把共用的数据放在redux中,一个组件中会既有state、props和redux存储数据,那么当页面出现问题,要从state、props和redux三个方面检查,开发程序是很快的,但是最费时间的是程序后期的可维护性和代码的可调节性。如果数据都放在redux中管理,项目出错以后,就只用检查redux,定位错位很快。不要想着state中的数据只会供一个组件使用,在项目越来越大的时候,说不准别的组件会需要使用,redux中可以存储5GB的数据。所以,能用redux的时候一定要用redux,对于后期的维护来说很方便

  • immutable,当你把reduximmutable这个库结合使用的时候,你整个项目的性能会达到最优,而且非常非常简单。没有数据臃肿的顾虑,你不存在redux中,你也需要存储在state或者props中。

  1. componentWillReceiveProps 的调用时机,答案如下所示:
  • 父组件中改变了props传值时触发的函数
  • props改变的时候才会调用,父组件第一次往子组件传值的时候,不会调用
  1. react 性能优化的最佳实践,答案如下所示:
  • PureComponent,自带shouldcomponentupdate,是一个浅比较,代码如下所示:
class Test extends React.PureComponents {
    constructor(props) {
        super(props)
    }
    
    render() {
        return <div>hello</div>
    }
}
  • 通过与immutable.js库的结合,完美的解决react的性能问题
  • 优化的核心是减少不必要的渲染
  • 增加shouldComponentUpdate钩子对新旧propsstate进行比较,如果值相同则阻止更新,避免不必要的渲染,或者使用PureReactComponent替代Component,其内部已经封装了shouldComponentUpdate的浅比较逻辑
  • 对于列表或其他结构相同的节点,为其中的每一项增加唯一key属性,以方便Reactdiff算法中对该节点的复用,减少节点的创建和删除操作
  • render函数中减少类似onClick={() => {doSomething()}}的写法,每次调用render函数时均会创建一个新的函数,即使内容没有发生任何变化,也会导致节点没必要的重渲染,建议将函数保存在组件的成员对象中,这样只会创建一次
  • webpack-bundle-analyzer分析当前页面的依赖包,是否存在不合理性
  1. 虚拟dom的理解,虚拟dom会提升代码性能的原因,答案如下所示:
  • 虚拟dom就是真实dom的一个js对象
  • 以前需要两个页面的差异,需要去比对真实dom的比对,真实的dom节点会有事件,属性,还会有各种各样的方法。所以两个真实dom的比对会非常耗性能。于是把dom对象变成js对象,js对象就没有dom对象上乱七八糟的特性了,js对象就比较快。
  1. webpack中,借助loader完成的JSX代码的转化,还是babel,答案如下所示:
  • babel - preset-react 所去完成的转化
  1. 调用setState后,发生的过程,答案如下所示:
  • 调用setState函数之后,react会将传入的参数对象与组件当前的状态合并,然后触发调和过程(Reconciliation),以高效方式根据新的状态构建React元素树并且着手重新渲染整个UI界面
  • React 得到元素树之后,React 会自动计算出新的树与老树的节点差异,然后根据差异对界面进行最小化重渲染,按需渲染,不是全部渲染
  • 调用函数,通过一个函数返回一个对象,代码如下所示:
this.setState({
    age: this.state.age + 1
}) // 如果是连续点击一个按钮调用这个setState,会出现数值不是一个一个加上去的,而是会出现一次几个的变化,因为react会把多个setState整合为一个,最后在改变state。

this.setState((prevState) => ({
    age: ++ prevState.age
})) // 不管你怎么疯狂的点击按钮,都会一个一个往上加。
  1. setState是异步的,这个点你在什么时候遇到过坑,答案如下所示:
  • 使用setState的时候返回传一个函数,同上所示
  • 对于setState 是异步还是同步主要看是谁在调用它,大部分情况下是异步的,小部分情况是同步的
  • 异步的情况,如下所示:
    • React 代理的合成事件中调用,如 onClick、onChange 事件,这些事件都是 React 为了代理原生事件而封装出来的一整套事件机制,我们称之为合成事件
    • 在钩子函数(生命周期)中调用
    • setState 的异步不是真的异步,setState 本身的执行过程是同步的,是 React 将多个 setState 进行合并和批量更新,导致其看起来像是异步的
  • 同步的情况,如下所示:
    • 在原生事件中调用,代码如下:

             class App extends React.Component{
            ...componentDidMount(){
                document.querySelector('#A').addEventListener('click',()=>{
                    this.setState({
                        // 这里的 setState 是同步的
                    })
                })
              }
            }
      
    • 在setTimeout()中调用

  1. refs的作用是什么,你在什么业务场景下使用过refs,答案如下所示:
  • refs的作用是操作dom,访问 DOM 元素或者某个组件实例
  • 在业务场景下使用过refs,展示一个图片,获取图片的宽高,这也是因为react不能直接操作dom
  • 放大镜,获取图片宽高等等
  • 当页面滚动,监听页面滚动的事件,代码如下所示:
class Test extends Component {
    // 需求:当页面滚动,监听页面滚动的事件
    constructor(props) {
        super(props);
        this.state = {
            top: 0
        }
        this.handleWindowScroll = this.handleWindowScroll.bind(this)
    }
    
    handleWindowScroll() {
        this.setState(() => ({
            top: document.body.scrollTop
        }))
    }
    
    componentDidMount() {
        window.addEventListener('scroll', this.handleWindowScroll)
    }
    
    componentWillUnmount() {
        window.removeEventListener('scroll', this.handleWindowScroll)
    }
    
    render() {
        return <div>{this.state.top}</div>
    }
}
  1. ref是一个函数,好处是什么,答案如下所示:
  • 方便react在销毁或者重新渲染组件的时候去有效的去清空ref里面的东西,防止内存泄漏,以后ref不要用字符串的形式了,要用函数式的写法
  • 代码如下所示:
class Test extends Component {
  componentDidMount() {
    this.elem
  }

  render() {
    return <div ref={(div) => { this.elem = div }}></div> // ref使用的时候最好使用函数
  }
}
  1. 高阶组件的理解,它的本质是什么,答案如下所示:
  • react里面不要去使用继承,为什么,设计模式中有这样一句话“组合优于继承”,react这种组件式的编程,是一种组合类型的设计模式,一定是优于继承的,可维护性是比继承高的多,react中所有问题都是可以利用组件拼合的方法解决的。
  • 高阶组件实际上就是一个函数,接收参数,返回参数。对一个组件进行包装,然后再返回一个组件。为什么对一个组件进行包装呢,因为组件有可能很多地方要用,这个组件的大部分东西在别的地方都可以直接用,只有少数的地方有区别,我们就可以把共用的地方写到高阶组件里面去,而通过往高阶组件里面传递参数,来去动态这个组件在使用时的差异。
  • 高阶组件地狱,新版本的hook解决了这个问题,代码如下所示:
<A>
  <B>
    <C>
      <D />
    </C>
  </B>
</A>
  • 高阶组件其实就是一个函数而已,只不过参数是一个组件而已,返回了一个新的组件。复用组件的业务逻辑 react-redux connect 其实就是一个高阶组件。HOC 是纯函数,没有副作用。纯函数是输入确定,输出就一定确定
  1. 受控组件和非受控组件的区别,答案如下所示:
  • HTML中,类似 <input/>, <select> 和 <textarea> 这样的表单元素会维护自身的状态,并基于用户的输入来更新。当用户提交表单时,前面提到的元素的值将随表单一起被发送。但在 React 中会有些不同,包含表单元素的组件将会在 state 中追踪输入的值,并且每次调用回调函数时,如 onChange 会更新 state,重新渲染组件。一个输入表单元素,它的值通过 React 的这种方式来控制,这样的元素就被称为"受控元素"
  • 受控组件:这个组件的改变完全受控于数据的变化,数据变了,页面变了
  • 非受控组件:input框,我直接操作dom,我不让他进行数据的绑定,输入完成点击按钮的时候,我直接通过refsdom上的内容来进行操作,不是通过数据来控制
  • 受控组件一定是更好的。react是一个数据驱动的框架,所以数据驱动是react核心,所以组件都应该被数据控制
  1. 函数组件和hooks,答案如下所示:
  • Hooks 技术,其作用让函数组件变得强大起来,它可以让 react 函数组件也拥有状态,让我们用现有的 JavaScript 技术就能快速上手,让我们获取数据、更改状态是如此的轻松
  • 使用 Hook 操作数据状态相比类组件更简洁,这也是函数式编程的魅力
  • 关于 Hooks 的内容比较多,比如常用的三个基本 Hook 功能:useState、useEffect、useContext,以及额外的方法:useRef、useReducer、useMemo、useCallback、useLayoutEffect、useDebugValue
  1. this指向问题的解决方法,答案如下所示:
  • 行间定义事件后面使用bind绑定this,这一种方法使用bind来修改this的指向,需要注意的是bind括号内第一个参数是修改this的,后面可以设置其他参数进行传值,代码如下所示:
	run(){
	        alert("第一种方法!")
	}

  	<button onClick={this.run.bind(this)}>第一种</button>

  • 在构造函数内部声明this指向,和第一种方法原理一样,只是写的位置不同,代码如下所示:
constructor(props) {
        super(props);
        this.state={
            //定义数据
        }
        this.run = this.run.bind(this);
    }
    
     run(){
            alert("第二种方法!")
      }
      
     <button onClick={this.run}>第二种</button>
  • 声明事件时将事件等于一个箭头函数,将定义的run方法再等于一个箭头函数,利用箭头函数没有自己的this指针会继承外层的作用域这个特性,来解决this指向问题,代码如下所示:
run=()=> {
	alert("第三种方法!")
  }

<button onClick={this.run}>第三种</button>
  • 行间定义事件使用箭头函数,和第三种方法的原理是一样的,只是写法不同,代码如下所示:
 run(){
	alert("第四种方法!")
  }

<button onClick={()=>this.run()>第四种</button>

  1. 函数组件怎么做性能优化,答案如下所示:
  • 函数式组件性能比普通组件性能高,因为函数组件没有类的其他属性,没有构造类的过程
  • 函数式组件,props发生变化以后,函数就会重新执行,React.memo(function Test() { return <div>123</div> }),这样包装,组件就会有shoulComponentUpdate这样的属性,这样函数式组件的性能一定要不普通组件的性能要好的
  • 函数式组件没有类的构造,生命周期,直接执行就可以,代码如下所示:
function Test() {
  return <div>123</div>
}

16.在哪个生命周期里发送ajax,答案如下所示:

  • 一定要在componentDidMount中去发送
  • componentWillMount在新版本的react中已经被废弃了,取而代之的是一个getDerivedStateFromProps这样一个生命周期函数,所以用componentWillMount不合适
  • 在用ssr项目中的时候,componentWillMount要做服务端数据的获取,所以不能被占用
  1. ssr的原理是什么,答案如下所示:
  • SSR,服务端渲染,React 代码在服务端上运行,直接生成带有数据的 HTML 页面( ajax 请求均在服务器上完成 ),然后直接将该页面返回给客户端,客户端只需解析 HTML 就能展示页面
  • 服务端渲染的优点,如下所示:
    • 更好的 SEO,因为在后端有完整的 HTML 页面,所以爬虫更容易爬取关键信息
    • 首屏渲染速度快,用户体验更好
    • 无需占用客户端资源,即解析模板的工作完全交由后端来做,客户端只要解析标准的 HTML 页面即可,这样对于客户端的资源占用更少,尤其是移动端,也可以更省电
    • 后端生成生成缓存片段,这样就可以减少数据库查询浪费的时间了,且对于数据变化不大的页面非常高效
  • 服务端渲染的缺点,如下所示:
    • 不利于前后端分离,开发效率低。使用服务器端渲染,则无法进行分工合作,则对于前端复杂度高的项目,不利于项目高效开发
    • 服务器压力变大,因为 React 代码由服务端执行并生成完成页面,当外部访问量增多,可能会出现页面加载变慢( 请求阻塞 )等情况,此时可以通过负载均衡策略解决
  • 适合 SSR 的项目,如下所示:
    • 项目要求SEOSSR 就很合适 ( 关于 SEO,预渲染也能做到 )
    • 需求项目某页面首屏时间要求很快,SSR 可以减少白屏时间
    • 首屏页数据请求多
  • react 服务端渲染的流程,如下所示:
    • 打包阶段会将业务代码打包两次,一份部署在服务端,一份用于客户端(可传到cdn
    • 然后启动服务,基于用户请求的路由决定render哪个页面,主要用到renderToStringapipage组件转化为html标记
    • 最简单的情况,将html标记直接返回客户端,渲染一个静态页面
    • 但实际业务中,一般在服务端需要获取数据,根据数据来生成html,这种情况下,当在客户端重新render时,如何保证数据一致呢,解决办法是将服务端获取到的数据以字符串的形式返回给客户端,客户端渲染的时候直接以该数据进行渲染,保证数据的一致性,进而保证了ui的一致性
    • 当在客户端运行时,主要用hydrateapihtml标记与js代码重新结合,之后就与服务端完全没关系了,可以当spa的情况处理
  • react 中实现 SSR 的核心原理,就是虚拟 DOM 的存在
  1. redux-saga的设计思想的理解,以及sideEffects 的理解,答案如下所示:
  • redux设计思想,web应用是一个状态机,视图与状态是一一对应的,所有的状态保存在一个对象里面
  • saga的应用整体思路,使用了Saga后,react只负责数据如何展示,redux来负责数据的状态和绑定数据到react,而Saga处理了大部分复杂的业务逻辑
  • app.js入口文件引入saga以及reducers,动态执行saga语句 middleware.run(sagas) 必须要在store创建好之后才能执行,在 store 之前执行,程序会报错。rootsage为所有模块组件的sage集合,用sage 副作用的all方法同时并发发出。引入action组件,发出action中定义好的action,用saga副作用处理函数 takeLatest(类似于防抖),执行最后一次请求。reducer文件对需要更改返回stateaction进行处理
  • redux-saga 就是 redux 的一个中间件,用于更优雅地管理副作用(side effects),redux-saga可以理解为一个和 系统交互的 常驻进程,可简单定义为 saga = Worker + Warcher
  • effect 是一个普通的 javascript对象,包含一些指令,这些指令最终会被 redux-saga 中间件 解释并执行。在 redux-saga 世界里,所有的 Effect 都必须被 yield 才会执行。原则上来说,所有的 yield 后面也只能跟Effect,以保证代码的易测性,taskgenerator 方法的执行环境,所有sagagenerator方法都跑在task
  • 作用是用于更优雅地管理副作用, 在前端就是异步网络请求;本质就是为了解决异步action的问题
  • 优点,如下所示:
    • 副作用转移到单独的saga.js中,不再掺杂在action.js中,保持 action 的简单纯粹,又使得异步操作集中可以被集中处理,对比redux-thunk
    • redux-saga 提供了丰富的 Effects,以及 sagas 的机制(所有的 saga 都可以被中断),在处理复杂的异步问题上更顺手。提供了更加细腻的控制流
    • 对比thunkdispatch 的参数依然是一个纯粹的 action (FSA)
    • 每一个 saga 都是 一个 generator function,代码可以采用 同步书写 的方式 去处理 异步逻辑(No Callback Hell),代码变得更易读
    • 同样是受益于 generator functionsaga 实现,代码异常/请求失败 都可以直接通过 try/catch 语法直接捕获处理
  1. reactjqueryvue是否有可能共存在一个项目中,答案如下所示:
  • 完全可以共存,关键看怎么共存
  1. 组件是什么?类是什么?类被编译成什么,答案如下所示:
  • 组件指的是页面的一部分,用类去实现,编译成一个构造函数
  • 模块是一个个webpack import引入的文件,ES6中的类在es5中就是构造函数
  1. 你是如何跟着社区成长的,答案如下所示:
  • 看英文官方文档,去学习相应的原理
  1. 如何避免ajax数据重新获取,答案如下所示:
  • 使用redux,判断数据有没有,有的话就不要再次请求
  1. react-router4的核心思想是什么,和react-router3有什么区别,答案如下所示:
  • react-router3的路由需要在一个文件内容易配置,而react-router4的理念则是把一个路由当做是一个组件,直接在组件中使用,这是react-router4react-router3在设计理念上的不同
  1. immutable.jsredux的最佳实践,答案如下所示:
  • immutable来自于函数式编程的世界,我们可以称它为不可变,相等性检查将包括两个部分,值检查和引用检查
  • React重新渲染,React通过对组件属性(props)和状态(state)进行变更检查以决定是否更新并重新渲染该组件,若组件状态太过庞大,组件性能就会下降,因为对象越复杂,其相等性检查就会越慢。对于嵌套对象,必须迭代层层进行检查判断,耗费时间过长。若仅修改对象的属性,其引用保持不变,相等性检查中的引用检查结果不变。Immutable提供一直简单快捷的方式以判断对象是否变更,对于React组件更新和重新渲染性能可以有较大帮助
  • Immutable数据,绝对不要突然修改对象,首先复制然后修改复制对象,再返回这个新对象,保持原对象不变。Immutable数据和原生JavaScript对象的主要差异为持久化数据结构和结构共享,如下所示:
    • 持久数据结构,主张所有操作都返回该数据结构的更新副本,并保持原有结构不变,而不是改变原来的结构。通常利用 Trie 构建它不可变的持久性数据结构,它的整体结构可以看作一棵树,一个树节点可以对应代表对象某一个属性,节点值即属性值
    • 结构共享,一旦创建一个Immutable Trie型对象,我们可以把该Trie型对象想象成如下一棵树,在之后的对象变更尽可能的重用树节点。当我们要更新一个Immutable对象的属性值时,就是对应着需要重构该Trie树中的某一个节点,对于Trie树,我们修改某一节点只需要重构该节点及受其影响的节点,即其祖先节点,如上图中的四个绿色节点,而其他节点可以完全重用
  • React组件状态必须是一个原生JavaScript对象,而不能是一个Immutable对象,因为ReactsetState 方法期望接受一个对象然后使用 Object.assign 方法将其与之前的状态对象合并,如下所示:
    • 使用Immutable.js的访问API访问state,如 get() , getIn()
    • 使用Immutable.js的集合操作生成组件子元素,使用高阶函数如 map() , reduce() 等创React元素的子元素
    • 使用Immutable.js的更新操作API更新state
  • 对于 Immutable.jsRedux实践,如下所示:
    • JavaScript对象转换为Immutable对象,如下所示:
      • 不要在Immutable对象中混用原生JavaScript对象
      • 当在Immutable对象内添加JavaScript对象时,首先使用 fromJS() 方法将JavaScript对象转换为Immutable对象,然后使用 update() , merge() , set() 等更新APIImmutable对象进行更新操作
    • Immutable与Redux state tree,如下所示:
      • 使用Immutable对象表示完整的Redux状态树,对于一个Redux应用,完整的状态树应该由一个Immutable对象表示,而没有原生JavaScript对象
      • 使用 fromJS() 方法创建状态树,状态树对象可以是一个Immutable.Record或者任何其他的实现了 get , set , withMutations 方法的Immutable集合的实例
      • 使用redux-immutable库调整 combineReducers 方法使其能处理Immutable
    • Immutable与Redux组件,如下所示:
      • 除了在展示型组件内,其他地方一律使用Immutable方式操作状态对象。为了保证应用性能,在容器组件,选择器(selectors),reducer函数,action创建函数,sagasthunks函数内等所有地方均使用Immutable,但是不在展示型组件内使用
      • 在容器组件内使用Immutable,容器组件可以使用react-redux提供的 connect 方法访问reduxstore,所以我们需要保证选择器(selectors)总是返回Immutable对象,否则,将会导致不必要的重新渲染。另外,我们可以使用诸如reselect的第三方库缓存选择器(selectors)以提高部分情景下的性能
    • Immutable对象转换为JavaScript对象,如下所示:
      • 绝对不要在 mapStateToProps方法内使用 toJS() 方法,toJS() 方法每次会调用时都是返回一个原生JavaScript对象,如果在 mapStateToProps 方法内使用 toJS() 方法,则每次状态树(Immutable对象)变更时,无论该 toJS() 方法返回的JavaScript对象是否实际发生改变,组件都会认为该对象发生变更,从而导致不必要的重新渲染
      • 绝对不要在展示型组件内使用 toJS() 方法,如果传递给某组件一个Immuatble对象类型的prop,则该组件的渲染取决于该Immutable对象,这将给组件的重用,测试和重构带来更多困难
      • 当容器组件将Immutable类型的属性(props)传入展示型组件时,需使用高阶组件(HOC)将其转换为原生JavaScript对象
  1. reselect是做什么使用的,答案如下所示:
  • 充当vue里面computed计算属性的角
  • 如果依赖的数据没有发生变化,计算属性就不会重新计算,做缓存提升代码性能
  • reselect的原理是,只要相关状态不变,即直接使用上一次的缓存结果
  • reselect通过创建选择器(selectors),该函数接受一个state参数,然后返回我们需要在 mapStateToProps 方法内返回对象的某一个数据项,一个选择器的处理可以分为两个步骤,如下所示:
    • 接受state参数,根据我们提供的映射函数数组分别进行计算,如果返回结果和上次第一步的计算结果一致,说明命中缓存,则不进行第二步计算,直接返回上次第二步的计算结果,否则继续第二步计算。第一步的结果比较,通常仅仅是 === 相等性检查,性能是足够的
    • 根据第一步返回的结果,计算,返回最终结果
  1. react-router基本原理,hashHistory,browserHistory,如下所示:
  • hashHistory: 不需要后端支持,hashHistory#
  • browserHistory:还需要后端在服务器上做配置
  1. 使用异步组件的情况,如下所示:
  • 异步组件,懒加载,按需加载
  • 如果可以,尽量在所有项目中使用,可以减小项目打包后的大小,在前端加载的时候,不会一次加载过大的js文件
  • Reloadable库,路由懒加载,按需加载,访问那个页面加载哪个页面代码
  1. XSS攻击在react中如何防范,如下所示:
  • react直接解析字符串,字符串带有script标签,标签内写有可执行的js代码,
    尽量在创建的时候转义
  • 代码如下所示:
<div dangerouslySetInnerHTML={{ __html: '<script>alert(1)</script>' }}></div>
  1. getDerivedStateFromProps,getSnapshotBeforeUpdate,如下所示:
  • getDerivedStateFromProps和componentWillReceiveProps差不多,可以对state进行一些更改
  • getSnapshotBeforeUpdate和componentWillUpdate差不多,想要获取更新之前的dom结构可以用它
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值