react 试题

react生命周期函数
这个问题要考察的是组件的生命周期
一、 初始化阶段:
getDefaultProps:获取实例的默认属性
getInitialState:获取每个实例的初始化状态
componentWillMount:组件即将被装载、渲染到页面上
render:组件在这里生成虚拟的DOM节点
componentDidMount:组件真正在被装载之后,最常用
二、 运行中状态:
componentWillReceiveProps:组件将要接收到属性的时候调用
shouldComponentUpdate(prestate, props):组件接受到新属性或者新状态的时候(可以返回false,接收数据后不更新,阻止render调用,后面的函数不会被继续执行了)
componentWillUpdate:组件即将更新不能修改属性和状态
render:组件重新描绘
componentDidUpdate:组件已经更新
三、 销毁阶段:
componentWillUnmount:组件即将销毁,清理工作,事件解除绑定,清理定时器,释放资源
详见:https://my.oschina.net/feiyangxiaomi/blog/644418
更改状态
this.state({}) //更常用 setState(fuction(){ //性能更好 return {} })
官方推荐第二种写法,因为function会存入队列中执行,可以提高性能,而第一种表示立即执行,(setState原理关键词:异步、队列、事务(transaction,一串批处理,完成全完成,失败全失败,保证数据的一致性))
//设count = 0 componentDidMount(){ this.setState({ count:this.state.count + 1 }) this.setState({ count:this.state.count + 1 }) } //最终渲染后state==1 componentDidMount(){ this.setState(function(preState, props){ return {count: preState + 1} }) this.setState(function(preState, props){ return {count: preState + 1} }) } //最终渲染后state==2
React使用refs取得多个dom的方式
参考文档:https://facebook.github.io/react/docs/refs-and-the-dom.html
1 构造器constructor中 声明 this.textInput = [];
2 render里面:
<input type="text" ref={(input) => { this.textInput.push(input); }} />
<input type="text" ref={(input) => { this.textInput.push(input); }} />
3 方法中可以用this.textInput取得多个
数据类型
Symbol,表示独一无二的值。它是 JavaScript 语言的第七种数据类型,前六种是:undefined、null、布尔值(Boolean)、字符串(String)、数值(Number)、对象(Object)。
react或者vue做prop验证的时候的类型。
String
Number
Boolean
Function
Object
Array
Symbol
JSX语法:
JS + XHTML的混写。
语法要求:
1.只能有一个顶层元素
2.组件首字母必须大写
3.html中的class应该写成className,for应该写成htmlFor。
4.标签必须封闭。
5.事件必须修正this指针。
constructor中写 this.fun = this.fun.bind(this)
onClick={()=>{}}
onClick={this.fun.bind(this)}
6.事件绑定时,事件的首字母要大写。 例如:onClick
2. 声明组件
ES5:
React.createClass({ render: function() { return ( html.... ) } })
ES6:
有状态组件
class App extends Component { render() { return ( html.... ) } }
无状态组件
const App = (props)=>( <div> .... </div> )
两者区别:
无状态组件没有this指针(因此不能绑定ref),没有state,唯一的参数是props
组件数据传递?
父-子 通过prop传递
子-父 在父中创建一个可以修改state的方法,之后把这个方法通过prop传递给子,在子中调用这个方法从而达到修改父state的目的。
非父子组件如何数据共享or数据通信:创建全局对象,监视对象on,数据发送方触发自定义事件同时传递数据。
var EventEmmiter = require("events").EventEmitter;
var obj = new Objcet(); Object.assign(obj ,EventEmmiter.protoype) obj.on("abc", function(data){ }) obj.emit("abc", data);
数据通信: axios whatwg-fetch
开发过哪些组件?
项目中常用到的组件比如:头部,底部、轮播图
在项目中使用轮播图,在github上找了几个轮播图插件,感觉都不好用,当图片数据是动态加载时往往就会出现错误(需要重新计算)。索性就自己在swiper的基础上进行了二次封装,要注意对数据进行校验
//AmazingSwiper.js import React, { Component } from 'react'; import Swiper from 'swiper'; import '../style/swiper.min.css'; export default class AmazingSwiper extends Component { componentDidUpdate() { console.log("new"); // 这里注意在update上进行绑定 var op = this.props.option; var sp = new Swiper(".swiper-container", { loop: op.loop ? op.loop : false, autoplay: op.autoplay ? {delay: 2500} : false }) } render() { console.log("a render"); let arr = this.props.ldata; return ( <div className="swiper-container"> <div className="swiper-wrapper"> {this.props.children} </div> </div> ) } } // Home.js render() { var arr = [ "https://pic.maizuo.com/usr/movie/c879dc398937b864f2424d7e1abf4edf.jpg", "https://pic.maizuo.com/usr/movie/d8dc842930a9744b7cc8c1eca7f6e402.jpg", "https://pic.maizuo.com/usr/movie/77780e34723cf9200071bec049c11ea4.jpg" ]; return ( <div> {this.state.position} <AmazingSwiper option={{autoplay:true, loop: true}}> { arr.map((item)=>{ return <div key={item} className="swiper-slide"><img src={item}/></div> }) } </AmazingSwiper> </div> ) }
使用create-react-app后创建的工程下有registerServiceWorker.js是做什么用的?
registerServiceWorker就是为react项目注册了一个service worker,用来做资源的缓存,这样你下次访问时,就可以更快的获取资源。而且因为资源被缓存,所以即使在离线的情况下也可以访问应用(此时使用的资源是之前缓存的资源)。注意,registerServiceWorker注册的service worker 只在生产环境中生效(process.env.NODE_ENV === ‘production’)
有了解过React.js吗?
React.js 只是一个视图库
(1)声明式设计
(2)高效:通过对DOM的模拟,最大限度的减少与DOM的交互。
(3)灵活:可以与已知的框架或库很好的配合。
(4)JSX:是js语法的扩展,不一定使用,但建议用。
(5)组件:构建组件,使代码更容易得到复用,能够很好地应用在大项目的开发中。
(6)单向响应的数据流:React实现了单向响应的数据流,从而减少了重复代码,这也是解释了它为什么比传统数据绑定更简单。
jsx语法使用时需要注意哪些内容?
{/*JSX 中的注释方式*/}
JSX中所有的标签都必须有闭标签
在JSX中我们通常是通过 {} 的方式插入值,但是设置style属性需要{{ }}
因为jsx最终要转成js进行编译,因此html标签上的属性名与JavaScript关键字和保留字相冲突的都需要做一些变化,其规则同js中操作dom属性时一样,
一般来说,在使用js操作标签属性时,若出现与JavaScript关键字和保留字相冲突的情况,除html标签class(转为className)以外的属性,在属性前加上小写的html即可,如
html标签的class在jsx语法中变为 className
html标签的for属性(如:<label for="msg" ></label>)在jsx中变为<label htmlFor="msg" ></label>,
import classes form './myCss.css' {/*调用.css 文件中的css属性, mycss 为css文件中的类*/} <div className={classes['mycss']}></div>
详见:http://www.cnblogs.com/fanlinqiang/p/7989255.html
react配置反向代理?
执行package.json中script定义的命令,即:npm run eject
"eject": "react-scripts eject"
tips:这个操作是不可逆的
在package.json文件中
"proxy": { "/v4": { "target": "https://m.maizuo.com", "changeOrigin": true, "pathRewrite": { "^/v4": "/v4" }, "ws": true } }
或者在webpackDevServer.config.js中配置,示例:
proxy: { '/api': { target: 'https://api.douban.com/', changeOrigin: true, pathRewrite: { '^/api': '' } } }
setState后发生了什么?
点击事件开始时,框架调用ReactEventListener.dispatchEvent
之后执行batchedUpdates开启事务。
setState中通过this.updater.enqueueSetState方法把state加入队列
(react-dom中实现了enqueueSetState方法)
事件绑定的方法执行完成以后,框架会继续执行batchedUpdates进行批量更新。
react性能优化是哪个周期函数?
shouldComponentUpdate这个方法用来判断是否需要调用render方法重新描绘dom。因为dom的描绘非常消耗性能,如果我们能在shouldComponentUpdate方法中能够写出更优化的dom diff算法,可以极大的提高性能。
详细参考:https://segmentfault.com/a/1190000006254212
为什么虚拟dom会提高性能?
虚拟dom相当于在js和真实dom中间加了一个缓存,利用dom diff算法避免了没有必要的dom操作,从而提髙性能。
具体实现步骤如下:
1. 用JavaScript对象结构表示DOM树的结构;然后用这个树构建一个真正的DOM树,插到文档当中
2.当状态变更的时候,重新构造一棵新的对象树。然后用新的树和旧的树进行比较,记录两棵树差异
3.把2所记录的差异应用到步骤1所构建的真正的DOM树上,视图就更新了。
参考链接:https://www.zhihu.com/question/29504639?sort=created
diff 算法?
1) 把树形结构按照层级分解,只比较同级元素。
2) 给列表结构的每个单元添加唯_的key属性,方便比较。
3) React只会匹配相同class的component (这里面的class指的是组件的名字)
4) 合并操作,调用component的setState方法的时候,React将其标记为dirty.到每一个事件循环 结束,React检查所有标记dirty的component重新绘制.
5) 选择性子树渲染。开发人员可以重写shouldComponentUpdate提高diff的性能。
参考链接:https://segmentfault.com/a/1190000000606216
react性能优化方案
1) 重写shouldComponentUpdate来避免不必要的dom操作0
2) 使用 production 版本的react.js0
3) 使用key来帮助React识别列表中所有子组件的最小变化。
参考链接:
https://segmentfault.com/a/1190000006254212 http://blog.csdn.net/limm33/article/details/50948869
React项目用过什么脚手架? Mern? Yeoman?
Mern: MERN是脚手架的工具,它可以很容易地使用Mongo, Express, React and NodeJS生成
同构JS应用。它最大限度地减少安装时间,并得到您使用的成熟技术来加速开发。
参考链接:http://www.open一open.com/lib/view/open1455953055292.html
当你调用setState的时候,发生了什么事?
当调用 setState 时,React会做的第一件事情是将传递给 setState 的对象合并到组件的当前状态。这将启动一个称为和解(reconciliation)的过程。和解(reconciliation)的最终目标是以最有效的方式,根据这个新的状态来更新UI。 为此,React将构建一个新的 React 元素树(您可以将其视为 UI 的对象表示)。
一旦有了这个树,为了弄清 UI 如何响应新的状态而改变,React 会将这个新树与上一个元素树相比较( diff )。
通过这样做, React 将会知道发生的确切变化,并且通过了解发生什么变化,只需在绝对必要的情况下进行更新即可最小化 UI 的占用空间。
无状态组件与有状态的组件的区别?
无状态组件:没有状态,没有生命周期,只是简单的接受 props 渲染生成 DOM 结构。无状态组件非常简单,开销很低,如果可能的话尽量使用无状态组件。
无状态的函数创建的组件是无状态组件,它是一种只负责展示的纯组件,可以使用纯函数来实现:
const HelloMessage = (props) => <div> Hello {props.name}</div>;
render(<HelloMessage name="John" />, mountNode);
无状态组件内部其实是可以使用ref功能的,虽然不能通过this.refs访问到,但是可以通过将ref内容保存到无状态组件内部的一个本地变量中获取到。
例如下面这段代码可以使用ref来获取组件挂载到DOM中后所指向的DOM元素:
function TestComp(props){ let ref; return ( <div ref={(node) => ref = node}></div> ) }
详见:https://www.w3cplus.com/react/stateful-vs-stateless-components.html
什么时候在功能组件( Class Component )上使用类组件( Functional Component )?
如果您的组件具有状态( state )或生命周期方法,请使用 Class 组件。否则,使用功能组件
可以选择性地传递给 setState 的第二个参数是什么,它的目的是什么?
一个回调函数,当setState结束并 re-rendered 该组件时将被调用。一些没有说出来的东西是 setState 是 异步 的,这就是为什么它需要一个第二个回调函数。通常最好使用另一个生命周期方法,而不是依赖这个回调函数,但是很高兴知道它存在。
this.setState(
{ username: 'tylermcginnis33' },
() => console.log('setState has finished and the component has re-rendered.')
)
this.setState的第二个参数的作用?
this.setState((prevState, props) => {
return {
streak: prevState.streak + props.count
}
})
这个函数格式是固定的,必须第一个参数是state的前一个状态,第二个参数是属性对象props,这两个对象setState会自动传递到函数中去,同时,这些函数在setState中的执行是同步的,从而解决了异步问题。但是这种写法很少被使用,并不是众所周知的,就是你也可以传递一个函数给setState,它接收到先前的状态和道具并返回一个新的状态,正如我们在上面所做的那样。它不仅没有什么问题,而且如果您根据以前的状态(state)设置状态,推荐使用这种写法。
双向数据绑定和单向数据的区别?
1.单向数据流中,父组件给子组件传递数据,但反过来不可以传递,也就是说单向数据流是从最外层节点传递到子节点,他们只需从最外层节点获取props渲染即可,如果顶层组件的 某个prop改变了,React会递归的向下便利整棵组件树,重新渲染所有使用这个属性的组件, React组件内部还具有自己的状态,这些状态只能在组件内修改;双向数据绑定是数据与视图 双向绑定,数据发生改变时,视图也改变,视图发生改变时,数据也会发生改变。
2.双向数据绑定的各种数据相互依赖相互绑定,导致数据问题的源头难以被跟踪到;单向 数据流的数据流动方向可以跟踪,流动单一,追查问题的时候可以更快捷,缺点是写起来不太方便,要使视图发生改变就得创建各种action来维护state。
双向绑定把数据变更的操作隐藏在框架内部,调用者并不会直接感知。而在践行单向数 据流的flux系的实现中,其实不过是在全局搞了一个单例的事件分发器(dispatcher),开发者 必须显式地通过这个统一的事件机制做数据变更通知。
在 React 当中 Element 和 Component 有何区别?
简单地说,一个 React element 描述了你想在屏幕上看到什么。换个说法就是,一个 React element 是一些 UI 的对象表示。
一个 React Component 是一个函数或一个类,它可以接受输入并返回一个 React element t(通常是通过 JSX ,它被转化成一个 createElement 调用)。
有关更多信息,请查看 React Elements vs React Components
组件是由元素构成的。元素数据结构是普通对象,而组件数据结构是类或纯函数。
详见:https://segmentfault.com/a/1190000008587988
什么是 React 的 refs ,为什么它们很重要?
refs就像是一个逃生舱口,允许您直接访问DOM元素或组件实例。为了使用它们,您可以向组件添加一个 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> ) } }
以上注意到我们的输入字段有一个 ref 属性,其值是一个函数。该函数接收我们然后放在实例上的实际的 DOM 元素,以便在 handleSubmit 函数内部访问它。经常误解的是,您需要使用类组件才能使用 ref ,但 ref 也可以通过利用 JavaScript 中的 闭包 与 功能组件( functional components )一起使用。
function CustomForm ({handleSubmit}) { let inputElement return ( <form onSubmit={() => handleSubmit(inputElement.value)}> <input type='text' ref={(input) => inputElement = input} /> <button type='submit'>Submit</button> </form> ) }
React 中的keys是什么,为什么它们很重要?
keys是什么帮助 React 跟踪哪些项目已更改、添加或从列表中删除。
return ( <ul> {this.state.todoItems.map(({task, uid}) => { return <li key={uid}>{task}</li> })} </ul> ) }
每个 keys 在兄弟元素之间是独一无二的。我们已经谈过几次关于和解(reconciliation)的过程,而且这个和解过程(reconciliation)中的一部分正在执行一个新的元素树与最前一个的差异。keys 使处理列表时更加高效,因为 React 可以使用子元素上的 keys 快速知道元素是新的还是在比较树时才被移动。
而且 keys 不仅使这个过程更有效率,而且没有 keys ,React 不知道哪个本地状态对应于移动中的哪个项目。所以当你 map 的时候,不要忽略了 keys 。
看下面的代码: 如果您在 下创建了一个 React 元素, 的组件定义将如何?
<Twitter username='tylermcginnis33'> {(user) => user === null ? <Loading /> : <Badge info={user} />} </Twitter> import React, { Component, PropTypes } from 'react' import fetchUser from 'twitter' // fetchUser接收用户名返回 promise // 当得到 用户的数据的时候 ,返回resolve 状态 class Twitter extends Component { // 在这里写下你的代码 }
如果你不熟悉渲染回调模式(render callback pattern),这将看起来有点奇怪。在这种模式中,一个组件接收一个函数作为它的 child。注意上面包含在 标签内的内容。 Twitter 组件的 child 是一个函数,而不是你曾经习以为常的一个组件。 这意味着在实现 Twitter 组件时,我们需要将 props.children 作为一个函数来处理。
以下是我的答案。
import React, { Component, PropTypes } from 'react'
import fetchUser from 'twitter'
class Twitter extends Component {
state = {
user: null,
}
static propTypes = {
username: PropTypes.string.isRequired,
}
componentDidMount () {
fetchUser(this.props.username)
.then((user) => this.setState({user}))
}
render () {
return this.props.children(this.state.user)
}
}
值得注意的是,正如我上面提到的,我通过调用它并传递给 user 来把 props.children 处理为为一个函数。
这种模式的好处是我们已经将我们的父组件与我们的子组件分离了。父组件管理状态,父组件的消费者可以决定以何种方式将从父级接收的参数应用于他们的 UI。
为了演示这一点,我们假设在另一个文件中,我们要渲染一个 Profile 而不是一个 Badge, ,因为我们使用渲染回调模式,所以我们可以轻松地交换 UI ,而不用改变我们对父(Twitter)组件的实现。
<Twitter username='tylermcginnis33'> {(user) => user === null ? <Loading /> : <Profile info={user} />} </Twitter>
受控组件( controlled component )与不受控制的组件( uncontrolled component )有什么区别?
React 的很大一部分是这样的想法,即组件负责控制和管理自己的状态。
当我们将 native HTML 表单元素( input, select, textarea 等)投入到组合中时会发生什么?我们是否应该使用 React 作为“单一的真理来源”,就像我们习惯使用React一样? 或者我们是否允许表单数据存在 DOM 中,就像我们习惯使用HTML表单元素一样? 这两个问题是受控(controlled) VS 不受控制(uncontrolled)组件的核心。
受控组件是React控制的组件,也是表单数据的唯一真理来源。
如下所示, username 不存在于 DOM 中,而是以我们的组件状态存在。每当我们想要更新 username 时,我们就像以前一样调用setState。
class ControlledForm extends Component { state = { username: '' } updateUsername = (e) => { this.setState({ username: e.target.value, }) } handleSubmit = () => {} render () { return ( <form onSubmit={this.handleSubmit}> <input type='text' value={this.state.username} onChange={this.updateUsername} /> <button type='submit'>Submit</button> </form> ) } }
不受控制( uncontrolled component )的组件是您的表单数据由 DOM 处理,而不是您的 React 组件。
我们使用 refs 来完成这个。
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> ) } }
虽然不受控制的组件通常更容易实现,因为您只需使用引用从DOM获取值,但是通常建议您通过不受控制的组件来支持受控组件。
主要原因是受控组件 支持即时字段验证 ,允许您有条件地禁用/启用按钮,强制输入格式,并且更多的是 『the React way』。
在哪个生命周期事件中你会发出 AJAX 请求,为什么?
AJAX 请求应该在 componentDidMount 生命周期事件中。 有几个原因:
- Fiber,是下一次实施React的和解算法,将有能力根据需要启动和停止渲染,以获得性能优势。其中一个取舍之一是
componentWillMount,而在其他的生命周期事件中出发 AJAX 请求,将是具有 “非确定性的”。 这意味着 React 可以在需要时感觉到不同的时间开始调用 componentWillMount。这显然是AJAX请求的不好的方式。
-您不能保证在组件挂载之前,AJAX请求将无法 resolve。如果这样做,那意味着你会尝试在一个未挂载的组件上设置 StState,这不仅不会起作用,反而会对你大喊大叫。 在 componentDidMount 中执行 AJAX 将保证至少有一个要更新的组件。
shouldComponentUpdate 应该做什么,为什么它很重要?
上面我们讨论了 reconciliation ,什么是 React 在 setState 被调用时所做的。在生命周期方法 shouldComponentUpdate 中,允许我们选择退出某些组件(和他们的子组件)的 reconciliation 过程。
我们为什么要这样做?
如上所述,“和解( reconciliation )的最终目标是以最有效的方式,根据新的状态更新用户界面”。如果我们知道我们的用户界面(UI)的某一部分不会改变,那么没有理由让 React 很麻烦地试图去弄清楚它是否应该渲染。通过从 shouldComponentUpdate 返回 false,React 将假定当前组件及其所有子组件将保持与当前组件相同。
您如何告诉React 构建(build)生产模式,该做什么?
通常,您将使用Webpack的 DefinePlugin 方法将 NODE_ENV 设置为 production。这将剥离像 propType 验证和额外的警告。除此之外,还有一个好主意,可以减少你的代码,因为React使用 Uglify 的 dead-code 来消除开发代码和注释,这将大大减少你的包的大小。
为什么要使用 React.Children.map(props.children,()=>) 而不是 props.children.map(()=>)
因为不能保证props.children将是一个数组。
以此代码为例,
<Parent> <h1>Welcome.</h1> </Parent>
在父组件内部,如果我们尝试使用 props.children.map 映射孩子,则会抛出错误,因为 props.children 是一个对象,而不是一个数组。
如果有多个子元素,React 只会使props.children成为一个数组。就像下面这样:
<Parent> <h1>Welcome.</h1> <h2>props.children will now be an array</h2> </Parent>
这就是为什么你喜欢 React.Children.map ,因为它的实现考虑到 props.children 可能是一个数组或一个对象。
描述事件在React中的处理方式。
为了解决跨浏览器兼容性问题,您的 React 中的事件处理程序将传递 SyntheticEvent 的实例,它是 React 的浏览器本机事件的跨浏览器包装器。
这些 SyntheticEvent 与您习惯的原生事件具有相同的接口,除了它们在所有浏览器中都兼容。有趣的是,React 实际上并没有将事件附加到子节点本身。React 将使用单个事件监听器监听顶层的所有事件。这对于性能是有好处的,这也意味着在更新DOM时,React 不需要担心跟踪事件监听器。
createElement 和 cloneElement 有什么区别?
createElement 是 JSX 被转载到的,是 React 用来创建 React Elements 的内容(一些 UI 的对象表示)cloneElement用于克隆元素并传递新的 props。他们钉住了这两个��的命名。
es7事件绑定this?


浙公网安备 33010602011771号