如何配置 React-Router 实现路由切换
(1)应用<Route>
组件
路由匹配是通过比拟 <Route>
的 path 属性和以后地址的 pathname 来实现的。当一个 <Route>
匹配胜利时,它将渲染其内容,当它不匹配时就会渲染 null。没有门路的 <Route>
将始终被匹配。
// when location = { pathname: '/about' }<Route path='/about' component={About}/> // renders <About/><Route path='/contact' component={Contact}/> // renders null<Route component={Always}/> // renders <Always/>
(2)联合应用 <Switch>
组件和 <Route>
组件
<Switch>
用于将 <Route>
分组。
<Switch> <Route exact path="/" component={Home} /> <Route path="/about" component={About} /> <Route path="/contact" component={Contact} /></Switch>
<Switch>
不是分组 <Route>
所必须的,但他通常很有用。 一个 <Switch>
会遍历其所有的子 <Route>
元素,并仅渲染与以后地址匹配的第一个元素。
(3)应用 <Link>、 <NavLink>、<Redirect>
组件
<Link>
组件来在你的应用程序中创立链接。无论你在何处渲染一个<Link>
,都会在应用程序的 HTML 中渲染锚(<a>
)。
<Link to="/">Home</Link> // <a href='/'>Home</a>
是一种非凡类型的 当它的 to属性与以后地址匹配时,能够将其定义为"沉闷的"。
// location = { pathname: '/react' }<NavLink to="/react" activeClassName="hurray"> React</NavLink>// <a href='/react' className='hurray'>React</a>
当咱们想强制导航时,能够渲染一个<Redirect>
,当一个<Redirect>
渲染时,它将应用它的to属性进行定向。
refs的作用是什么,你在什么样的业务场景下应用refs
- 操作DOM,为什么操作DOM?
场景
- 图片渲染好后,操作图片宽高。比方做个放大镜性能
React组件命名举荐的形式是哪个?
通过援用而不是应用来命名组件displayName。
应用displayName命名组件:
export default React.createClass({ displayName: 'TodoApp', // ...})
React举荐的办法:
export default class TodoApp extends React.Component { // ...}
当渲染一个列表时,何为 key?设置 key 的目标是什么
Keys 会有助于 React 辨认哪些 items
扭转了,被增加了或者被移除了。Keys 应该被赋予数组内的元素以赋予(DOM)元素一个稳固的标识,抉择一个 key 的最佳办法是应用一个字符串,该字符串能惟一地标识一个列表项。很多时候你会应用数据中的 IDs 作为 keys,当你没有稳固的 IDs 用于被渲染的 items
时,能够应用我的项目索引作为渲染项的 key,但这种形式并不举荐,如果 items
能够从新排序,就会导致 re-render
变慢。
Redux 和 Vuex 有什么区别,它们的独特思维
(1)Redux 和 Vuex区别
- Vuex改良了Redux中的Action和Reducer函数,以mutations变动函数取代Reducer,无需switch,只需在对应的mutation函数里扭转state值即可
- Vuex因为Vue主动从新渲染的个性,无需订阅从新渲染函数,只有生成新的State即可
- Vuex数据流的程序是∶View调用store.commit提交对应的申请到Store中对应的mutation函数->store扭转(vue检测到数据变动主动渲染)
艰深点了解就是,vuex 弱化 dispatch,通过commit进行 store状态的一次更变;勾销了action概念,不用传入特定的 action模式进行指定变更;弱化reducer,基于commit参数间接对数据进行转变,使得框架更加繁难;
(2)独特思维
- 单—的数据源
- 变动能够预测
实质上∶ redux与vuex都是对mvvm思维的服务,将数据从视图中抽离的一种计划。
为什么调用 setState 而不是间接扭转 state?
解答
如果您尝试间接扭转组件的状态,React 将无奈得悉它须要从新渲染组件。通过应用setState()
办法,React 能够更新组件的UI。
另外,您还能够谈谈如何不保障状态更新是同步的。如果须要基于另一个状态(或属性)更新组件的状态,请向setState()
传递一个函数,该函数将 state 和 props 作为其两个参数:
this.setState((state, props) => ({ counter: state.counter + props.increment}));
React-Router的实现原理是什么?
客户端路由实现的思维:
基于 hash 的路由:通过监听
hashchange
事件,感知 hash 的变动- 扭转 hash 能够间接通过 location.hash=xxx
基于 H5 history 路由:
- 扭转 url 能够通过 history.pushState 和 resplaceState 等,会将URL压入堆栈,同时可能利用
history.go()
等 API - 监听 url 的变动能够通过自定义事件触发实现
- 扭转 url 能够通过 history.pushState 和 resplaceState 等,会将URL压入堆栈,同时可能利用
react-router 实现的思维:
- 基于
history
库来实现上述不同的客户端路由实现思维,并且可能保留历史记录等,磨平浏览器差别,下层无感知 - 通过保护的列表,在每次 URL 发生变化的回收,通过配置的 路由门路,匹配到对应的 Component,并且 render
参考:前端react面试题具体解答
React申明组件有哪几种办法,有什么不同?
React 申明组件的三种形式:
- 函数式定义的
无状态组件
- ES5原生形式
React.createClass
定义的组件 - ES6模式的
extends React.Component
定义的组件
(1)无状态函数式组件 它是为了创立纯展现组件,这种组件只负责依据传入的props来展现,不波及到state状态的操作
组件不会被实例化,整体渲染性能失去晋升,不能拜访this对象,不能拜访生命周期的办法
(2)ES5 原生形式 React.createClass // RFC React.createClass会自绑定函数办法,导致不必要的性能开销,减少代码过期的可能性。
(3)E6继承模式 React.Component // RCC 目前极为举荐的创立有状态组件的形式,最终会取代React.createClass模式;绝对于 React.createClass能够更好实现代码复用。
无状态组件绝对于于后者的区别: 与无状态组件相比,React.createClass和React.Component都是创立有状态的组件,这些组件是要被实例化的,并且能够拜访组件的生命周期办法。
React.createClass与React.Component区别:
① 函数this自绑定
- React.createClass创立的组件,其每一个成员函数的this都有React主动绑定,函数中的this会被正确设置。
- React.Component创立的组件,其成员函数不会主动绑定this,须要开发者手动绑定,否则this不能获取以后组件实例对象。
② 组件属性类型propTypes及其默认props属性defaultProps配置不同
- React.createClass在创立组件时,无关组件props的属性类型及组件默认的属性会作为组件实例的属性来配置,其中defaultProps是应用getDefaultProps的办法来获取默认组件属性的
- React.Component在创立组件时配置这两个对应信息时,他们是作为组件类的属性,不是组件实例的属性,也就是所谓的类的动态属性来配置的。
③ 组件初始状态state的配置不同
- React.createClass创立的组件,其状态state是通过getInitialState办法来配置组件相干的状态;
- React.Component创立的组件,其状态state是在constructor中像初始化组件属性一样申明的。
Redux 怎么实现属性传递,介绍下原理
react-redux 数据传输∶ view-->action-->reducer-->store-->view。看下点击事件的数据是如何通过redux传到view上:
- view 上的AddClick 事件通过mapDispatchToProps 把数据传到action ---> click:()=>dispatch(ADD)
- action 的ADD 传到reducer上
- reducer传到store上 const store = createStore(reducer);
- store再通过 mapStateToProps 映射穿到view上text:State.text
代码示例∶
import React from 'react';import ReactDOM from 'react-dom';import { createStore } from 'redux';import { Provider, connect } from 'react-redux';class App extends React.Component{ render(){ let { text, click, clickR } = this.props; return( <div> <div>数据:已有人{text}</div> <div onClick={click}>加人</div> <div onClick={clickR}>减人</div> </div> ) }}const initialState = { text:5}const reducer = function(state,action){ switch(action.type){ case 'ADD': return {text:state.text+1} case 'REMOVE': return {text:state.text-1} default: return initialState; }}let ADD = { type:'ADD'}let Remove = { type:'REMOVE'}const store = createStore(reducer);let mapStateToProps = function (state){ return{ text:state.text }}let mapDispatchToProps = function(dispatch){ return{ click:()=>dispatch(ADD), clickR:()=>dispatch(Remove) }}const App1 = connect(mapStateToProps,mapDispatchToProps)(App);ReactDOM.render( <Provider store = {store}> <App1></App1> </Provider>,document.getElementById('root'))
为什么应用jsx的组件中没有看到应用react却须要引入react?
实质上来说JSX是React.createElement(component, props, ...children)
办法的语法糖。在React 17之前,如果应用了JSX,其实就是在应用React, babel
会把组件转换为 CreateElement
模式。在React 17之后,就不再须要引入,因为 babel
曾经能够帮咱们主动引入react。
应该在 React 组件的何处发动 Ajax 申请
在 React 组件中,应该在 componentDidMount
中发动网络申请。这个办法会在组件第一次“挂载”(被增加到 DOM)时执行,在组件的生命周期中仅会执行一次。更重要的是,你不能保障在组件挂载之前 Ajax 申请曾经实现,如果是这样,也就意味着你将尝试在一个未挂载的组件上调用 setState,这将不起作用。在 componentDidMount
中发动网络申请将保障这有一个组件能够更新了。
react16的谬误边界(Error Boundaries)是什么
局部 UI 中的 JavaScript 谬误不应该毁坏整个应用程序。 为了解决 React 用户的这个问题,React 16引入了一个 “谬误边界(Error Boundaries)” 的新概念。
import React from 'react';import ReactDOM from 'react-dom';class ErrorBoundary extends React.Component{ constructor(props) { super(props); this.state={hasError:false}; } componentDidCatch(err,info) { this.setState({hasError: true}); } render() { if (this.state.hasError) { return <h1>Something Went Wrong</h1> } return this.props.children; }}class Page extends React.Component{ render() { return ( <ErrorBoundary> <Clock/> </ErrorBoundary> ) }}class Clock extends React.Component{ render() { return ( <div>hello{null.toString()}</div> ) }}ReactDOM.render(<Page/>,document.querySelector('#root'));
对React-Fiber的了解,它解决了什么问题?
React V15 在渲染时,会递归比对 VirtualDOM 树,找出须要变动的节点,而后同步更新它们, 零打碎敲。这个过程期间, React 会占据浏览器资源,这会导致用户触发的事件得不到响应,并且会导致掉帧,导致用户感觉到卡顿。
为了给用户制作一种利用很快的“假象”,不能让一个工作长期霸占着资源。 能够将浏览器的渲染、布局、绘制、资源加载(例如 HTML 解析)、事件响应、脚本执行视作操作系统的“过程”,须要通过某些调度策略正当地调配 CPU 资源,从而进步浏览器的用户响应速率, 同时兼顾工作执行效率。
所以 React 通过Fiber 架构,让这个执行过程变成可被中断。“适时”地让出 CPU 执行权,除了能够让浏览器及时地响应用户的交互,还有其余益处:
- 分批延时对DOM进行操作,防止一次性操作大量 DOM 节点,能够失去更好的用户体验;
- 给浏览器一点喘息的机会,它会对代码进行编译优化(JIT)及进行热代码优化,或者对 reflow 进行修改。
核心思想: Fiber 也称协程或者纤程。它和线程并不一样,协程自身是没有并发或者并行能力的(须要配合线程),它只是一种管制流程的让出机制。让出 CPU 的执行权,让 CPU 能在这段时间执行其余的操作。渲染的过程能够被中断,能够将控制权交回浏览器,让位给高优先级的工作,浏览器闲暇后再复原渲染。
React的事件和一般的HTML事件有什么不同?
区别:
- 对于事件名称命名形式,原生事件为全小写,react 事件采纳小驼峰;
- 对于事件函数解决语法,原生事件为字符串,react 事件为函数;
- react 事件不能采纳 return false 的形式来阻止浏览器的默认行为,而必须要地明确地调用
preventDefault()
来阻止默认行为。
合成事件是 react 模仿原生 DOM 事件所有能力的一个事件对象,其长处如下:
- 兼容所有浏览器,更好的跨平台;
- 将事件对立寄存在一个数组,防止频繁的新增与删除(垃圾回收)。
- 不便 react 对立治理和事务机制。
事件的执行程序为原生事件先执行,合成事件后执行,合成事件会冒泡绑定到 document 上,所以尽量避免原生事件与合成事件混用,如果原生事件阻止冒泡,可能会导致合成事件不执行,因为须要冒泡到document 上合成事件才会执行。
Redux 原理及工作流程
(1)原理 Redux源码次要分为以下几个模块文件
- compose.js 提供从右到左进行函数式编程
- createStore.js 提供作为生成惟一store的函数
- combineReducers.js 提供合并多个reducer的函数,保障store的唯一性
- bindActionCreators.js 能够让开发者在不间接接触dispacth的前提下进行更改state的操作
- applyMiddleware.js 这个办法通过中间件来加强dispatch的性能
const actionTypes = { ADD: 'ADD', CHANGEINFO: 'CHANGEINFO',}const initState = { info: '初始化',}export default function initReducer(state=initState, action) { switch(action.type) { case actionTypes.CHANGEINFO: return { ...state, info: action.preload.info || '', } default: return { ...state }; }}export default function createStore(reducer, initialState, middleFunc) { if (initialState && typeof initialState === 'function') { middleFunc = initialState; initialState = undefined; } let currentState = initialState; const listeners = []; if (middleFunc && typeof middleFunc === 'function') { // 封装dispatch return middleFunc(createStore)(reducer, initialState); } const getState = () => { return currentState; } const dispatch = (action) => { currentState = reducer(currentState, action); listeners.forEach(listener => { listener(); }) } const subscribe = (listener) => { listeners.push(listener); } return { getState, dispatch, subscribe }}
(2)工作流程
- const store= createStore(fn)生成数据;
- action: {type: Symble('action01), payload:'payload' }定义行为;
- dispatch发动action:store.dispatch(doSomething('action001'));
- reducer:解决action,返回新的state;
艰深点解释:
- 首先,用户(通过View)收回Action,收回形式就用到了dispatch办法
- 而后,Store主动调用Reducer,并且传入两个参数:以后State和收到的Action,Reducer会返回新的State
- State—旦有变动,Store就会调用监听函数,来更新View
以 store 为外围,能够把它看成数据存储核心,然而他要更改数据的时候不能间接批改,数据批改更新的角色由Reducers来负责,store只做存储,中间人,当Reducers的更新实现当前会通过store的订阅来告诉react component,组件把新的状态从新获取渲染,组件中也能被动发送action,创立action后这个动作是不会执行的,所以要dispatch这个action,让store通过reducers去做更新React Component 就是react的每个组件。
React 高阶组件是什么,和一般组件有什么区别,实用什么场景
官网解释∶
高阶组件(HOC)是 React 中用于复用组件逻辑的一种高级技巧。HOC 本身不是 React API 的一部分,它是一种基于 React 的组合个性而造成的设计模式。
高阶组件(HOC)就是一个函数,且该函数承受一个组件作为参数,并返回一个新的组件,它只是一种组件的设计模式,这种设计模式是由react本身的组合性质必然产生的。咱们将它们称为纯组件,因为它们能够承受任何动静提供的子组件,但它们不会批改或复制其输出组件中的任何行为。
// hoc的定义function withSubscription(WrappedComponent, selectData) { return class extends React.Component { constructor(props) { super(props); this.state = { data: selectData(DataSource, props) }; } // 一些通用的逻辑解决 render() { // ... 并应用新数据渲染被包装的组件! return <WrappedComponent data={this.state.data} {...this.props} />; } };// 应用const BlogPostWithSubscription = withSubscription(BlogPost, (DataSource, props) => DataSource.getBlogPost(props.id));
1)HOC的优缺点
- 长处∶ 逻辑服用、不影响被包裹组件的外部逻辑。
- 毛病∶hoc传递给被包裹组件的props容易和被包裹后的组件重名,进而被笼罩
2)实用场景
- 代码复用,逻辑形象
- 渲染劫持
- State 形象和更改
- Props 更改
3)具体利用例子
- 权限管制: 利用高阶组件的 条件渲染 个性能够对页面进行权限管制,权限管制个别分为两个维度:页面级别和 页面元素级别
// HOC.jsfunction withAdminAuth(WrappedComponent) { return class extends React.Component { state = { isAdmin: false, } async UNSAFE_componentWillMount() { const currentRole = await getCurrentUserRole(); this.setState({ isAdmin: currentRole === 'Admin', }); } render() { if (this.state.isAdmin) { return <WrappedComponent {...this.props} />; } else { return (<div>您没有权限查看该页面,请分割管理员!</div>); } } };}// pages/page-a.jsclass PageA extends React.Component { constructor(props) { super(props); // something here... } UNSAFE_componentWillMount() { // fetching data } render() { // render page with data }}export default withAdminAuth(PageA);// pages/page-b.jsclass PageB extends React.Component { constructor(props) { super(props); // something here... } UNSAFE_componentWillMount() { // fetching data } render() { // render page with data }}export default withAdminAuth(PageB);
- 组件渲染性能追踪: 借助父组件子组件生命周期规定捕捉子组件的生命周期,能够不便的对某个组件的渲染工夫进行记录∶
class Home extends React.Component { render() { return (<h1>Hello World.</h1>); } } function withTiming(WrappedComponent) { return class extends WrappedComponent { constructor(props) { super(props); this.start = 0; this.end = 0; } UNSAFE_componentWillMount() { super.componentWillMount && super.componentWillMount(); this.start = Date.now(); } componentDidMount() { super.componentDidMount && super.componentDidMount(); this.end = Date.now(); console.log(`${WrappedComponent.name} 组件渲染工夫为 ${this.end - this.start} ms`); } render() { return super.render(); } }; } export default withTiming(Home);
留神:withTiming 是利用 反向继承 实现的一个高阶组件,性能是计算被包裹组件(这里是 Home 组件)的渲染工夫。
- 页面复用
const withFetching = fetching => WrappedComponent => { return class extends React.Component { state = { data: [], } async UNSAFE_componentWillMount() { const data = await fetching(); this.setState({ data, }); } render() { return <WrappedComponent data={this.state.data} {...this.props} />; } }}// pages/page-a.jsexport default withFetching(fetching('science-fiction'))(MovieList);// pages/page-b.jsexport default withFetching(fetching('action'))(MovieList);// pages/page-other.jsexport default withFetching(fetching('some-other-type'))(MovieList);
React组件的state和props有什么区别?
(1)props
props是一个从内部传进组件的参数,次要作为就是从父组件向子组件传递数据,它具备可读性和不变性,只能通过内部组件被动传入新的props来从新渲染子组件,否则子组件的props以及展示模式不会扭转。
(2)state
state的次要作用是用于组件保留、管制以及批改本人的状态,它只能在constructor中初始化,它算是组件的公有属性,不可通过内部拜访和批改,只能通过组件外部的this.setState来批改,批改state属性会导致组件的从新渲染。
(3)区别
- props 是传递给组件的(相似于函数的形参),而state 是在组件内被组件本人治理的(相似于在一个函数内申明的变量)。
- props 是不可批改的,所有 React 组件都必须像纯函数一样爱护它们的 props 不被更改。
- state 是在组件中创立的,个别在 constructor中初始化 state。state 是多变的、能够批改,每次setState都异步更新的。
用户不同权限 能够查看不同的页面 如何实现?
- Js形式
依据用户权限类型,把菜单配置成json, 没有权限的间接不显示 - react-router 形式 在route 标签上 增加onEnter事件,进入路由之前替换到首页
<Route path="/home" component={App} onEnter={(nexState,replace)=>{ if(nexState.location.pathname!=='/'){ var sid = UtilsMoudle.getSidFromUrl(nexState); if(!sid){ replace("/") }else{ console.log(sid); } } }}>
- 本人封装一个privateRouter组件 外面判断是否有权限,有的话返回
<Route path={path} component={component} exact={exact}/>
没有权限的话component 返回一个提示信息的组件。 - 扩大一下,如果是依据用权限来判断是否暗藏组件该怎么做呢?
react 能够应用高阶组件,在高阶组件外面判断是否有权限,而后判断是否返回组件,无权限返回null
vue 能够应用自定义指令,如果没有权限移除组件
// 须要在入口处增加自定义权限指令v-auth,显示可操作组件Vue.directive('auth', { bind: function (el, binding, vnode) { // 用户权限表 const rules = auths for (let i = 0; i < rules.length; i++) { const item = rules[i] if(!binding.value || (binding.value == item.auth)){ // 权限容许则显示组件 return true } } // 移除组件 el.parentNode.removeChild(el) }})// 应用<template> <div> <Button v-auth="admin_user_add">增加用户</Button> <Button v-auth="admin_user_del">删除用户</Button> <Button v-auth="admin_user_edit">编辑用户</Button> </div></template>
什么起因会促使你脱离 create-react-app 的依赖
当你想去配置 webpack 或 babel presets。
对 React Hook 的了解,它的实现原理是什么
React-Hooks 是 React 团队在 React 组件开发实际中,逐步认知到的一个改良点,这背地其实波及对类组件和函数组件两种组件模式的思考和偏重。
(1)类组件: 所谓类组件,就是基于 ES6 Class 这种写法,通过继承 React.Component 得来的 React 组件。以下是一个类组件:
class DemoClass extends React.Component { state = { text: "" }; componentDidMount() { //... } changeText = (newText) => { this.setState({ text: newText }); }; render() { return ( <div className="demoClass"> <p>{this.state.text}</p> <button onClick={this.changeText}>批改</button> </div> ); }}
能够看出,React 类组件外部预置了相当多的“现成的货色”等着咱们去调度/定制,state 和生命周期就是这些“现成货色”中的典型。要想得到这些货色,难度也不大,只须要继承一个 React.Component 即可。
当然,这也是类组件的一个不便,它太繁冗了,对于解决许多问题来说,编写一个类组件切实是一个过于简单的姿态。简单的姿态必然带来昂扬的了解老本,这也是咱们所不想看到的。除此之外,因为开发者编写的逻辑在封装后是和组件粘在一起的,这就使得类组件外部的逻辑难以实现拆分和复用。
(2)函数组件:函数组件就是以函数的状态存在的 React 组件。晚期并没有 React-Hooks,函数组件外部无奈定义和保护 state,因而它还有一个别名叫“无状态组件”。以下是一个函数组件:
function DemoFunction(props) { const { text } = props return ( <div className="demoFunction"> <p>{`函数组件接管的内容:[${text}]`}</p> </div> );}
相比于类组件,函数组件肉眼可见的特质天然包含轻量、灵便、易于组织和保护、较低的学习老本等。
通过比照,从状态上能够对两种组件做辨别,它们之间的区别如下:
- 类组件须要继承 class,函数组件不须要;
- 类组件能够拜访生命周期办法,函数组件不能;
- 类组件中能够获取到实例化后的 this,并基于这个 this 做各种各样的事件,而函数组件不能够;
- 类组件中能够定义并保护 state(状态),而函数组件不能够;
除此之外,还有一些其余的不同。通过下面的区别,咱们不能说谁好谁坏,它们各有本人的劣势。在 React-Hooks 呈现之前,类组件的能力边界显著强于函数组件。
实际上,类组件和函数组件之间,是面向对象和函数式编程这两套不同的设计思维之间的差别。而函数组件更加符合 React 框架的设计理念: React 组件自身的定位就是函数,一个输出数据、输入 UI 的函数。作为开发者,咱们编写的是申明式的代码,而 React 框架的次要工作,就是及时地把申明式的代码转换为命令式的 DOM 操作,把数据层面的形容映射到用户可见的 UI 变动中去。这就意味着从原则上来讲,React 的数据应该总是紧紧地和渲染绑定在一起的,而类组件做不到这一点。函数组件就真正地将数据和渲染绑定到了一起。函数组件是一个更加匹配其设计理念、也更有利于逻辑拆分与重用的组件表达形式。
为了能让开发者更好的的去编写函数式组件。于是,React-Hooks 便应运而生。
React-Hooks 是一套可能使函数组件更弱小、更灵便的“钩子”。
函数组件比起类组件少了很多货色,比方生命周期、对 state 的治理等。这就给函数组件的应用带来了十分多的局限性,导致咱们并不能应用函数这种模式,写出一个真正的全功能的组件。而React-Hooks 的呈现,就是为了帮忙函数组件补齐这些(绝对于类组件来说)缺失的能力。
如果说函数组件是一台笨重的快艇,那么 React-Hooks 就是一个内容丰盛的零部件箱。“重装战舰”所预置的那些设施,这个箱子里根本全都有,同时它还不强制你全都要,而是容许你自在地抉择和应用你须要的那些能力,而后将这些能力以 Hook(钩子)的模式“钩”进你的组件里,从而定制出一个最适宜你的“专属战舰”。