redux中间件
中间件提供第三方插件的模式,自定义拦挡action
->reducer
的过程。变为action
->middlewares
->reducer
。这种机制能够让咱们扭转数据流,实现如异步action
,action
过滤,日志输入,异样报告等性能
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
,匹配 /login
到 Login
,所以须要两个 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计算等耗时绝对短。