关于react.js:React面试八股文第一期

52次阅读

共计 9910 个字符,预计需要花费 25 分钟才能阅读完成。

react 有什么特点

  • react 应用过的虚构 DOM,而不是实在 DOM
  • react 能够用服务器渲染
  • react 遵循单向数据流 或者数据绑定

React 数据长久化有什么实际吗?

封装数据长久化组件:

let storage={
    // 减少
    set(key, value){localStorage.setItem(key, JSON.stringify(value));
    },
    // 获取
    get(key){return JSON.parse(localStorage.getItem(key));
    },
    // 删除
    remove(key){localStorage.removeItem(key);
    }
};
export default Storage;

在 React 我的项目中,通过 redux 存储全局数据时,会有一个问题,如果用户刷新了网页,那么通过 redux 存储的全局数据就会被全副清空,比方登录信息等。这时就会有全局数据长久化存储的需要。首先想到的就是 localStorage,localStorage 是没有工夫限度的数据存储,能够通过它来实现数据的长久化存储。

然而在曾经应用 redux 来治理和存储全局数据的根底上,再去应用 localStorage 来读写数据,这样不仅是工作量微小,还容易出错。那么有没有联合 redux 来达到持久数据存储性能的框架呢?当然,它就是redux-persist。redux-persist 会将 redux 的 store 中的数据缓存到浏览器的 localStorage 中。其应用步骤如下:

(1)首先要装置 redux-persist:

npm i redux-persist

(2)对于 reducer 和 action 的解决不变,只需批改 store 的生成代码,批改如下:

import {createStore} from 'redux'
import reducers from '../reducers/index'
import {persistStore, persistReducer} from 'redux-persist';
import storage from 'redux-persist/lib/storage';
import autoMergeLevel2 from 'redux-persist/lib/stateReconciler/autoMergeLevel2';
const persistConfig = {
    key: 'root',
    storage: storage,
    stateReconciler: autoMergeLevel2 // 查看 'Merge Process' 局部的具体情况
};
const myPersistReducer = persistReducer(persistConfig, reducers)
const store = createStore(myPersistReducer)
export const persistor = persistStore(store)
export default store

(3)在 index.js 中,将 PersistGate 标签作为网页内容的父标签:

import React from 'react';
import ReactDOM from 'react-dom';
import {Provider} from 'react-redux'
import store from './redux/store/store'
import {persistor} from './redux/store/store'
import {PersistGate} from 'redux-persist/lib/integration/react';
ReactDOM.render(<Provider store={store}>
            <PersistGate loading={null} persistor={persistor}>
                {/* 网页内容 */}            </PersistGate>
        </Provider>, document.getElementById('root'));

这就实现了通过 redux-persist 实现 React 长久化本地数据存储的简略利用。

React 生命周期函数

挂载阶段

挂载阶段也能够了解为初始化阶段,也就是把咱们的组件插入到 DOM 中。

  • constructor
  • getDerivedStateFromProps
  • ~~UNSAFE_componentWillMount~~
  • render
  • (React Updates DOM and refs)
  • componentDidMount
  • constructor

组件的构造函数,第一个被执行。显式定义构造函数时,须要在第一行执行 super(props),否则不能再构造函数中拿到 this

在构造函数中,咱们个别会做两件事:

  • 初始化 state
  • 对自定义办法进行 this 绑定
  • getDerivedStateFromProps

是一个动态函数,所以不能在这里应用 this,也表明了 React 官网不心愿调用方滥用这个生命周期函数。每当父组件引发以后组件的渲染过程时,getDerivedStateFromProps 都会被调用,这样咱们有机会依据新的 props 和以后的 state 来调整一个新的 state。

这个函数会在收到新的 props,调用了 setState 或 forceUpdate 时被调用。

  1. render

React 最外围的办法,class 组件中必须实现的办法。

当 render 被调用时,它会查看 this.propsthis.state 的变动并返回一下类型之一:

  • 原生的 DOM,如 div
  • React 组件
  • 数组或 Fragment
  • Portals(传送门)
  • 字符串或数字,被渲染成文本节点
  • 布尔值或 null,不会渲染任何货色
  • componentDidMount

在组件挂载之后立刻调用。依赖于 DOM 节点的初始化应该放在这里。如需通过网络申请获取数据,此处是实例化申请的好中央。这个办法比拟适宜增加订阅的中央,如果增加了订阅,请记得在卸载的时候勾销订阅。

你能够在 componentDidMount 外面间接调用 setState,它将触发额定渲染,但此渲染会产生在浏览器更新屏幕之前,如此保障了即便 render 了两次,用户也不会看到中间状态。

更新阶段

更新阶段是指当组件的 props 产生了扭转,或者组件外部调用了 setState 或者产生了 forceUpdate,这个阶段的过程包含:

  • UNSAFE_componentWillReceiveProps
  • getDerivedStateFromProps
  • sholdComponentUpdate
  • UNSAFE_componentWIllUpdate
  • render
  • getSnapshotBeforeUpdate
  • (React Updates DOM and refs)
  • componentDidUpdate
  • shouldComponentUpdate

它有两个参数,依据此函数的返回值来判断是否从新进行渲染,首次渲染或者是当咱们调用了 forceUpdate 时并不会触发此办法,此办法仅用于性能优化。

然而官网提倡咱们应用内置的 PureComponent 而不是本人编写 shouldComponentUpdate。

  1. getSnapshotBeforeUpdate

这个生命周期函数产生在 render 之后,在更新之前,给了一个机会去获取 DOM 信息,计算失去并返回一个 snapshot,这个 snapshot 会作为 componentDidUpdate 第三个参数传入。

  1. componentDidUpdate

这个函数会在更新后被立刻调用,首次渲染不会执行此办法。在这个函数中咱们能够操作 DOM,能够发动申请,还能够 setState,但留神肯定要用条件语句,否则会导致有限循环。

卸载阶段

  1. componentWillUnmount

这个生命周期函数会在组件卸载销毁之前被调用,咱们能够在这里执行一些革除操作。不要在这里调用 setState,因为组件不会从新渲染。

对 Redux 的了解,次要解决什么问题

React 是视图层框架。Redux 是一个用来治理数据状态和 UI 状态的 JavaScript 利用工具。随着 JavaScript 单页利用(SPA)开发日趋简单,JavaScript 须要治理比任何时候都要多的 state(状态),Redux 就是升高治理难度的。(Redux 反对 React、Angular、jQuery 甚至纯 JavaScript)。

在 React 中,UI 以组件的模式来搭建,组件之间能够嵌套组合。但 React 中组件间通信的数据流是单向的,顶层组件能够通过 props 属性向上层组件传递数据,而上层组件不能向下层组件传递数据,兄弟组件之间同样不能。这样简略的单向数据流撑持起了 React 中的数据可控性。

当我的项目越来越大的时候,治理数据的事件或回调函数将越来越多,也将越来越不好治理。治理一直变动的 state 十分艰难。如果一个 model 的变动会引起另一个 model 变动,那么当 view 变动时,就可能引起对应 model 以及另一个 model 的变动,顺次地,可能会引起另一个 view 的变动。直至你搞不清楚到底产生了什么。state 在什么时候,因为什么起因,如何变动未然不受管制。当零碎变得盘根错节的时候,想重现问题或者增加新性能就会变得举步维艰。如果这还不够蹩脚,思考一些来自前端开发畛域的新需要,如更新调优、服务端渲染、路由跳转前申请数据等。state 的治理在大我的项目中相当简单。

Redux 提供了一个叫 store 的对立仓储库,组件通过 dispatch 将 state 间接传入 store,不必通过其余的组件。并且组件通过 subscribe 从 store 获取到 state 的扭转。应用了 Redux,所有的组件都能够从 store 中获取到所需的 state,他们也能从 store 获取到 state 的扭转。这比组件之间相互传递数据清晰清朗的多。

次要解决的问题: 单纯的 Redux 只是一个状态机,是没有 UI 出现的,react- redux 作用是将 Redux 的状态机和 React 的 UI 出现绑定在一起,当你 dispatch action 扭转 state 的时候,会自动更新页面。

redux 有什么毛病

  • 一个组件所须要的数据,必须由父组件传过来,而不能像 flux 中间接从 store 取。
  • 当一个组件相干数据更新时,即便父组件不须要用到这个组件,父组件还是会从新 render,可能会有效率影响,或者须要写简单的shouldComponentUpdate 进行判断。

如何用 React 构建(build)生产模式?

通常,应用 Webpack 的 DefinePlugin 办法将 NODE ENV 设置为 production。这将剥离 propType 验证和额定的正告。除此之外,还能够缩小代码,因为 React 应用 Uglify 的 dead-code 来打消开发代码和正文,这将大大减少包占用的空间。

setState 办法的第二个参数有什么用?应用它的目标是什么?

它是一个回调函数,当 setState 办法执行完结并从新渲染该组件时调用它。在工作中,更好的形式是应用 React 组件生命周期之——“存在期”的生命周期办法,而不是依赖这个回调函数。

export class App extends Component {constructor(props) {super(props);
    this.state = {username: "雨夜清荷",};
  }
  render() {return <div> {this.state.username}</div>;
  }
  componentDidMount() {
    this.setstate(
      {username: "有课前端网",},
      () => console.log("re-rendered success.")
    );
  }
}

在 Redux 中应用 Action 要留神哪些问题?

在 Redux 中应用 Action 的时候,Action 文件里尽量放弃 Action 文件的污浊,传入什么数据就返回什么数据,最妤把申请的数据和 Action 办法分来到,以放弃 Action 的污浊。

react 组件的划分业务组件技术组件?

  • 依据组件的职责通常把组件分为 UI 组件和容器组件。
  • UI 组件负责 UI 的出现,容器组件负责管理数据和逻辑。
  • 两者通过 React-Redux 提供connect 办法分割起来

参考:前端 react 面试题具体解答

传入 setstate 函数的第二个参数的作用是什么?

第二个参数是一个函数,该函数会在 setState 函数调用实现并且组件开始重渲染时调用,能够用该函数来监听渲染是否实现。

this.setstate(
  {username: "有课前端网",},
  () => console.log("re-rendered success.")
);

React 如何判断什么时候从新渲染组件?

组件状态的扭转能够因为 props 的扭转,或者间接通过 setState 办法扭转。组件取得新的状态,而后 React 决定是否应该从新渲染组件。只有组件的 state 发生变化,React 就会对组件进行从新渲染。这是因为 React 中的 shouldComponentUpdate 办法默认返回true,这就是导致每次更新都从新渲染的起因。

当 React 将要渲染组件时会执行 shouldComponentUpdate 办法来看它是否返回 true(组件应该更新,也就是从新渲染)。所以须要重写shouldComponentUpdate 办法让它依据状况返回 true 或者 false 来通知 React 什么时候从新渲染什么时候跳过从新渲染。

React 的 Fiber 工作原理,解决了什么问题

  • React Fiber 是一种基于浏览器的单线程调度算法。

React Fiber 用相似 requestIdleCallback 的机制来做异步 diff。然而之前数据结构不反对这样的实现异步 diff,于是 React 实现了一个相似链表的数据结构,将原来的 递归 diff 变成了当初的 遍历 diff,这样就能做到异步可更新了

react-router 里的 <Link> 标签和 <a> 标签有什么区别

比照 <a>,Link 组件防止了不必要的重渲染

React 中什么是受控组件和非控组件?

(1)受控组件 在应用表单来收集用户输出时,例如<input><select><textearea> 等元素都要绑定一个 change 事件,当表单的状态发生变化,就会触发 onChange 事件,更新组件的 state。这种组件在 React 中被称为 受控组件,在受控组件中,组件渲染出的状态与它的 value 或 checked 属性绝对应,react 通过这种形式打消了组件的部分状态,使整个状态可控。react 官网举荐应用受控表单组件。

受控组件更新 state 的流程:

  • 能够通过初始 state 中设置表单的默认值
  • 每当表单的值发生变化时,调用 onChange 事件处理器
  • 事件处理器通过事件对象 e 拿到扭转后的状态,并更新组件的 state
  • 一旦通过 setState 办法更新 state,就会触发视图的从新渲染,实现表单组件的更新

受控组件缺点: 表单元素的值都是由 React 组件进行治理,当有多个输入框,或者多个这种组件时,如果想同时获取到全副的值就必须每个都要编写事件处理函数,这会让代码看着很臃肿,所以为了解决这种状况,呈现了非受控组件。

(2)非受控组件 如果一个表单组件没有 value props(单选和复选按钮对应的是 checked props)时,就能够称为非受控组件。在非受控组件中,能够应用一个 ref 来从 DOM 取得表单值。而不是为每个状态更新编写一个事件处理程序。

React 官网的解释:

要编写一个非受控组件,而不是为每个状态更新都编写数据处理函数,你能够应用 ref 来从 DOM 节点中获取表单数据。
因为非受控组件将实在数据贮存在 DOM 节点中,所以在应用非受控组件时,有时候反而更容易同时集成 React 和非 React 代码。如果你不介意代码好看性,并且心愿疾速编写代码,应用非受控组件往往能够缩小你的代码量。否则,你应该应用受控组件。

例如,上面的代码在非受控组件中接管单个属性:

class NameForm extends React.Component {constructor(props) {super(props);
    this.handleSubmit = this.handleSubmit.bind(this);
  }
  handleSubmit(event) {alert('A name was submitted:' + this.input.value);
    event.preventDefault();}
  render() {
    return (<form onSubmit={this.handleSubmit}>
        <label>
          Name:          <input type="text" ref={(input) => this.input = input} />        </label>
        <input type="submit" value="Submit" />
      </form>
    );
  }
}

总结: 页面中所有输出类的 DOM 如果是现用现取的称为非受控组件,而通过 setState 将输出的值保护到了 state 中,须要时再从 state 中取出,这里的数据就受到了 state 的管制,称为受控组件。

说说你用 react 有什么坑点?

1. JSX 做表达式判断时候,须要强转为 boolean 类型

如果不应用 !!b 进行强转数据类型,会在页面外面输入 0

render() {
  const b = 0;
  return <div>
    {!!b && <div> 这是一段文本 </div>}
  </div>
}

2. 尽量不要在 componentWillReviceProps 里应用 setState,如果肯定要应用,那么须要判断完结条件,不然会呈现有限重渲染,导致页面解体

3. 给组件增加 ref 时候,尽量不要应用匿名函数,因为当组件更新的时候,匿名函数会被当做新的 prop 解决,让 ref 属性承受到新函数的时候,react 外部会先清空 ref,也就是会以 null 为回调参数先执行一次 ref 这个 props,而后在以该组件的实例执行一次 ref,所以用匿名函数做 ref 的时候,有的时候去 ref 赋值后的属性会取到 null

4. 遍历子节点的时候,不要用 index 作为组件的 key 进行传入

如何有条件地向 React 组件增加属性?

对于某些属性,React 十分聪慧,如果传递给它的值是虚值,能够省略该属性。例如:

var InputComponent = React.createClass({render: function () {
    var required = true;
    var disabled = false;
    return <input type="text" disabled={disabled} required={required} />;
  },
});

渲染后果:

<input type="text" required>

另一种可能的办法是:

var condition = true;
var component = <div value="foo" {...(condition && { disabled: true})} />;

HOC 相比 mixins 有什么长处?

HOC 和 Vue 中的 mixins 作用是统一的,并且在晚期 React 也是应用 mixins 的形式。然而在应用 class 的形式创立组件当前,mixins 的形式就不能应用了,并且其实 mixins 也是存在一些问题的,比方:

  • 隐含了一些依赖,比方我在组件中写了某个 state 并且在 mixin 中应用了,就这存在了一个依赖关系。万一下次他人要移除它,就得去 mixin 中查找依赖
  • 多个 mixin 中可能存在雷同命名的函数,同时代码组件中也不能呈现雷同命名的函数,否则就是重写了,其实我始终感觉命名真的是一件麻烦事。。
  • 雪球效应,尽管我一个组件还是应用着同一个 mixin,然而一个 mixin 会被多个组件应用,可能会存在需要使得 mixin 批改本来的函数或者新增更多的函数,这样可能就会产生一个保护老本

HOC 解决了这些问题,并且它们达成的成果也是统一的,同时也更加的政治正确(毕竟更加函数式了)。

当调用 setState 时,React render 是如何工作的?

咱们能够将 ”render“ 分为两个步骤:

  1. 虚构 DOM 渲染: 当 render 办法被调用时,它返回一个新的组件的虚构 DOM 构造。当调用 setState() 时,render会被再次调用,因为默认状况下 shouldComponentUpdate 总是返回true,所以默认状况下 React 是没有优化的。
  2. 原生 DOM 渲染:React 只会在虚构 DOM 中批改实在 DOM 节点,而且批改的次数非常少——这是很棒的 React 个性,它优化了实在 DOM 的变动,使 React 变得更快。

React-Router 4 的 Switch 有什么用?

Switch 通常被用来包裹 Route,用于渲染与门路匹配的第一个子 <Route><Redirect>,它外面不能放其余元素。

如果不加 <Switch>

import {Route} from 'react-router-dom'

<Route path="/" component={Home}></Route>
<Route path="/login" component={Login}></Route>

Route 组件的 path 属性用于匹配门路,因为须要匹配 /Home,匹配 /loginLogin,所以须要两个 Route,然而不能这么写。这样写的话,当 URL 的 path 为“/login”时,<Route path="/" /><Route path="/login" /> 都会被匹配,因而页面会展现 Home 和 Login 两个组件。这时就须要借助 <Switch> 来做到只显示一个匹配组件:

import {Switch, Route} from 'react-router-dom'

<Switch>
    <Route path="/" component={Home}></Route>
    <Route path="/login" component={Login}></Route>
</Switch>

此时,再拜访“/login”门路时,却只显示了 Home 组件。这是就用到了 exact 属性,它的作用就是准确匹配门路,常常与<Switch> 联结应用。只有当 URL 和该 <Route> 的 path 属性完全一致的状况下能力匹配上:

import {Switch, Route} from 'react-router-dom'

<Switch>
   <Route exact path="/" component={Home}></Route>
   <Route exact path="/login" component={Login}></Route>
</Switch>

react router

import React from 'react'
import {render} from 'react-dom'
import {browserHistory, Router, Route, IndexRoute} from 'react-router'

import App from '../components/App'
import Home from '../components/Home'
import About from '../components/About'
import Features from '../components/Features'

render(<Router history={browserHistory}>  // history 路由
    <Route path='/' component={App}>
      <IndexRoute component={Home} />
      <Route path='about' component={About} />
      <Route path='features' component={Features} />
    </Route>
  </Router>,
  document.getElementById('app')
)
render(<Router history={browserHistory} routes={routes} />,
  document.getElementById('app')
)

React Router 提供一个 routerWillLeave 生命周期钩子,这使得 React 组件能够拦挡正在产生的跳转,或在来到 route 前提醒用户。routerWillLeave 返回值有以下两种:

return false 勾销此次跳转
return 返回提示信息,在来到 route 前提醒用户进行确认。

正文完
 0