redux中间件

中间件提供第三方插件的模式,自定义拦挡 action -> reducer 的过程。变为 action -> middlewares -> reducer。这种机制能够让咱们扭转数据流,实现如异步actionaction 过滤,日志输入,异样报告等性能
  • redux-logger:提供日志输入
  • redux-thunk:解决异步操作
  • redux-promise:解决异步操作,actionCreator的返回值是promise

React中refs的作用是什么?有哪些利用场景?

Refs 提供了一种形式,用于拜访在 render 办法中创立的 React 元素或 DOM 节点。Refs 应该审慎应用,如下场景应用 Refs 比拟适宜:

  • 解决焦点、文本抉择或者媒体的管制
  • 触发必要的动画
  • 集成第三方 DOM 库

Refs 是应用 React.createRef() 办法创立的,他通过 ref 属性附加到 React 元素上。要在整个组件中应用 Refs,须要将 ref 在构造函数中调配给其实例属性:

class MyComponent extends React.Component {  constructor(props) {    super(props)    this.myRef = React.createRef()  }  render() {    return <div ref={this.myRef} />  }}

因为函数组件没有实例,因而不能在函数组件上间接应用 ref

function MyFunctionalComponent() {  return <input />;}class Parent extends React.Component {  constructor(props) {    super(props);    this.textInput = React.createRef();  }  render() {    // 这将不会工作!    return (      <MyFunctionalComponent ref={this.textInput} />    );  }}

但能够通过闭合的帮忙在函数组件外部进行应用 Refs:

function CustomTextInput(props) {  // 这里必须申明 textInput,这样 ref 回调才能够援用它  let textInput = null;  function handleClick() {    textInput.focus();  }  return (    <div>      <input        type="text"        ref={(input) => { textInput = input; }} />      <input        type="button"        value="Focus the text input"        onClick={handleClick}      />    </div>  );  }

留神:

  • 不应该适度的应用 Refs
  • ref 的返回值取决于节点的类型:

    • ref 属性被用于一个一般的 HTML 元素时,React.createRef() 将接管底层 DOM 元素作为他的 current 属性以创立 ref
    • ref 属性被用于一个自定义的类组件时,ref 对象将接管该组件已挂载的实例作为他的 current
  • 当在父组件中须要拜访子组件中的 ref 时可应用传递 Refs 或回调 Refs。

diff算法如何比拟?

  • 只对同级比拟,跨层级的dom不会进行复用
  • 不同类型节点生成的dom树不同,此时会间接销毁老节点及子孙节点,并新建节点
  • 能够通过key来对元素diff的过程提供复用的线索
  • 单节点diff
  • 单点diff有如下几种状况:
  • key和type雷同示意能够复用节点
  • key不同间接标记删除节点,而后新建节点
  • key雷同type不同,标记删除该节点和兄弟节点,而后新创建节点

如何解决 props 层级过深的问题

  • 应用Context API:提供一种组件之间的状态共享,而不用通过显式组件树逐层传递props;
  • 应用Redux等状态库。

React的事件和一般的HTML事件有什么不同?

区别:

  • 对于事件名称命名形式,原生事件为全小写,react 事件采纳小驼峰;
  • 对于事件函数解决语法,原生事件为字符串,react 事件为函数;
  • react 事件不能采纳 return false 的形式来阻止浏览器的默认行为,而必须要地明确地调用preventDefault()来阻止默认行为。

合成事件是 react 模仿原生 DOM 事件所有能力的一个事件对象,其长处如下:

  • 兼容所有浏览器,更好的跨平台;
  • 将事件对立寄存在一个数组,防止频繁的新增与删除(垃圾回收)。
  • 不便 react 对立治理和事务机制。

事件的执行程序为原生事件先执行,合成事件后执行,合成事件会冒泡绑定到 document 上,所以尽量避免原生事件与合成事件混用,如果原生事件阻止冒泡,可能会导致合成事件不执行,因为须要冒泡到document 上合成事件才会执行。

react-router 里的 Link 标签和 a 标签的区别

从最终渲染的 DOM 来看,这两者都是链接,都是 标签,区别是∶ <Link>是react-router 里实现路由跳转的链接,个别配合<Route> 应用,react-router接管了其默认的链接跳转行为,区别于传统的页面跳转,<Link> 的“跳转”行为只会触发相匹配的<Route>对应的页面内容更新,而不会刷新整个页面。

<Link>做了3件事件:

  • 有onclick那就执行onclick
  • click的时候阻止a标签默认事件
  • 依据跳转href(即是to),用history (web前端路由两种形式之一,history & hash)跳转,此时只是链接变了,并没有刷新页面而<a>标签就是一般的超链接了,用于从以后页面跳转到href指向的另一 个页面(非锚点状况)。

a标签默认事件禁掉之后做了什么才实现了跳转?

let domArr = document.getElementsByTagName('a')[...domArr].forEach(item=>{    item.addEventListener('click',function () {        location.href = this.href    })})

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面试题具体解答

redux 有什么毛病

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

react有什么长处

  • 进步利用性能
  • 能够不便的在客户端和服务端应用
  • 应用jsx模板进行数据渲染,可读性好

createElement过程

React.createElement(): 依据指定的第一个参数创立一个React元素
React.createElement(  type,  [props],  [...children])
  • 第一个参数是必填,传入的是似HTML标签名称,eg: ul, li
  • 第二个参数是选填,示意的是属性,eg: className
  • 第三个参数是选填, 子节点,eg: 要显示的文本内容
//写法一:var child1 = React.createElement('li', null, 'one');    var child2 = React.createElement('li', null, 'two');    var content = React.createElement('ul', { className: 'teststyle' }, child1, child2); // 第三个参数能够离开也能够写成一个数组      ReactDOM.render(          content,        document.getElementById('example')      );//写法二:var child1 = React.createElement('li', null, 'one');    var child2 = React.createElement('li', null, 'two');    var content = React.createElement('ul', { className: 'teststyle' }, [child1, child2]);      ReactDOM.render(          content,        document.getElementById('example')      );

Redux外部原理 外部怎么实现dispstch一个函数的

redux-thunk中间件作为例子,上面就是thunkMiddleware函数的代码
// 局部转为ES5代码,运行middleware函数会返回一个新的函数,如下:return ({ dispatch, getState }) => {    // next理论就是传入的dispatch    return function (next) {        return function (action) {            // redux-thunk外围            if (typeof action === 'function') {                 return action(dispatch, getState, extraArgument);            }            return next(action);        };    };}
redux-thunk库外部源码十分的简略,容许action是一个函数,同时反对参数传递,否则调用办法不变
  • redux创立Store:通过combineReducers函数合并reducer函数,返回一个新的函数combination(这个函数负责循环遍历运行reducer函数,返回全副state)。将这个新函数作为参数传入createStore函数,函数外部通过dispatch,初始化运行传入的combination,state生成,返回store对象
  • redux中间件:applyMiddleware函数中间件的次要目标就是批改dispatch函数,返回通过中间件解决的新的dispatch函数
  • redux应用:理论就是再次调用循环遍历调用reducer函数,更新state

什么是 React Context?

Context 通过组件树提供了一个传递数据的办法,从而防止了在每一个层级手动的传递 props 属性。

Dva工作原理

集成redux+redux-saga

工作原理

扭转产生通常是通过用户交互行为或者浏览器行为(如路由跳转等)触发的,当此类行为会扭转数据的时候能够通过 dispatch 发动一个 action,如果是同步行为会间接通过 Reducers 扭转 State ,如果是异步行为(副作用)会先触发 Effects 而后流向 Reducers 最终扭转 State

mobox 和 redux 有什么区别?

(1)共同点

  • 为了解决状态管理混乱,无奈无效同步的问题对立保护治理利用状态;
  • 某一状态只有一个可信数据起源(通常命名为store,指状态容器);
  • 操作更新状态形式对立,并且可控(通常以action形式提供更新状态的路径);
  • 反对将store与React组件连贯,如react-redux,mobx- react;

(2)区别 Redux更多的是遵循Flux模式的一种实现,是一个 JavaScript库,它关注点次要是以下几方面∶

  • Action∶ 一个JavaScript对象,形容动作相干信息,次要蕴含type属性和payload属性∶

    o type∶ action 类型; o payload∶ 负载数据;
  • Reducer∶ 定义利用状态如何响应不同动作(action),如何更新状态;
  • Store∶ 治理action和reducer及其关系的对象,次要提供以下性能∶

    o 保护利用状态并反对拜访状态(getState());o 反对监听action的散发,更新状态(dispatch(action)); o 反对订阅store的变更(subscribe(listener));
  • 异步流∶ 因为Redux所有对store状态的变更,都应该通过action触发,异步工作(通常都是业务或获取数据工作)也不例外,而为了不将业务或数据相干的工作混入React组件中,就须要应用其余框架配合治理异步工作流程,如redux-thunk,redux-saga等;

Mobx是一个通明函数响应式编程的状态治理库,它使得状态治理简略可伸缩∶

  • Action∶定义扭转状态的动作函数,包含如何变更状态;
  • Store∶ 集中管理模块状态(State)和动作(action)
  • Derivation(衍生)∶ 从利用状态中派生而出,且没有任何其余影响的数据

比照总结:

  • redux将数据保留在繁多的store中,mobx将数据保留在扩散的多个store中
  • redux应用plain object保留数据,须要手动解决变动后的操作;mobx实用observable保留数据,数据变动后主动解决响应的操作
  • redux应用不可变状态,这意味着状态是只读的,不能间接去批改它,而是应该返回一个新的状态,同时应用纯函数;mobx中的状态是可变的,能够间接对其进行批改
  • mobx相对来说比较简单,在其中有很多的形象,mobx更多的应用面向对象的编程思维;redux会比较复杂,因为其中的函数式编程思维把握起来不是那么容易,同时须要借助一系列的中间件来解决异步和副作用
  • mobx中有更多的形象和封装,调试会比拟艰难,同时后果也难以预测;而redux提供可能进行工夫回溯的开发工具,同时其纯函数以及更少的形象,让调试变得更加的容易

react-redux 的实现原理?

通过 redux 和 react context 配合应用,并借助高阶函数,实现了 react-redux

React 中 refs 干嘛用的?

Refs 提供了一种拜访在render办法中创立的 DOM 节点或者 React 元素的办法。在典型的数据流中,props 是父子组件交互的惟一形式,想要批改子组件,须要应用新的pros从新渲染它。凡事有例外,某些状况下咱们须要在典型数据流外,强制批改子代,这个时候能够应用 Refs
咱们能够在组件增加一个 ref 属性来应用,该属性的值是一个回调函数,接管作为其第一个参数的底层 DOM 元素或组件的挂载实例。

class UnControlledForm extends Component {  handleSubmit = () => {    console.log("Input Value: ", this.input.value);  };  render() {    return (      <form onSubmit={this.handleSubmit}>        <input type="text" ref={(input) => (this.input = input)} />        <button type="submit">Submit</button>      </form>    );  }}

请留神,input 元素有一个ref属性,它的值是一个函数。该函数接管输出的理论 DOM 元素,而后将其放在实例上,这样就能够在 handleSubmit 函数外部拜访它。
常常被误会的只有在类组件中能力应用 refs,然而refs也能够通过利用 JS 中的闭包与函数组件一起应用。

function CustomForm({ handleSubmit }) {  let inputElement;  return (    <form onSubmit={() => handleSubmit(inputElement.value)}>      <input type="text" ref={(input) => (inputElement = input)} />      <button type="submit">Submit</button>    </form>  );}

依据上面定义的代码,能够找出存在的两个问题吗 ?

请看上面的代码:

答案:
1.在构造函数没有将 props 传递给 super,它应该包含以下行

constructor(props) {super(props);// ...}

2.事件监听器(通过addEventListener()调配时)的作用域不正确,因为 ES6 不提供主动绑定。因而,开发人员能够在构造函数中重新分配clickHandler来蕴含正确的绑定:

constructor(props) {super(props);this.clickHandler = this.clickHandler.bind(this);// ...}

非嵌套关系组件的通信形式?

即没有任何蕴含关系的组件,包含兄弟组件以及不在同一个父级中的非兄弟组件。

  • 能够应用自定义事件通信(公布订阅模式)
  • 能够通过redux等进行全局状态治理
  • 如果是兄弟组件通信,能够找到这两个兄弟节点独特的父节点, 联合父子间通信形式进行通信。

为什么不间接更新 state 呢 ?

如果试图间接更新 state ,则不会从新渲染组件。

// 谬误This.state.message = 'Hello world';

须要应用setState()办法来更新 state。它调度对组件state对象的更新。当state扭转时,组件通过从新渲染来响应:

// 正确做法This.setState({message: ‘Hello World’});

react16版本的reconciliation阶段和commit阶段是什么

  • reconciliation阶段蕴含的次要工作是对current tree 和 new tree 做diff计算,找出变动局部。进行遍历、比照等是能够中断,歇一会儿接着再来。
  • commit阶段是对上一阶段获取到的变动局部利用到实在的DOM树中,是一系列的DOM操作。不仅要保护更简单的DOM状态,而且中断后再持续,会对用户体验造成影响。在广泛的利用场景下,此阶段的耗时比diff计算等耗时绝对短。