1.react生命周期
广义上分为三个阶段:挂载、渲染、卸载
1.初始化阶段
getDefaultProps()设置默认的props,在es6中使用组件名.defaultProps设置组件的默认属性
getInitialState()es6的class语法是没有这个钩子函数的,可以直接在constructor中定义this.state,此时可以访问this.props
componentWillMount()-渲染之前执行,在客户端和服务器都会执行
render()创建虚拟DOM,进行diff算法,更新dom树都在此进行,此时不能更改state
componentDidMount()-仅在第一次渲染后再客户端执行,将虚拟DOM转为真的DOM
2.更新阶段
componentWillReceiveProps(nextProps)-当从父类接收到props并且在调用另一个渲染器之前调用
shouldComponentUpdate(nextProps, nextState)-根据特定条件返回true或false,如果希望组件更新,返回true,否则false
componentWillUpdate(nextProps, nextState)组件初始化不调用,组件将要更新时调用,此时可以修改state
render()组件渲染
componentDidUpdate() 组件初始化不调用,组件更新完成后调用,此时可以获取dom节点
3.卸载阶段
componentWillUnmount() – 从 DOM 卸载组件后调用。用于清理内存空间。一些事件的监听和定时需要此时清除
------------------------------------------------------------------------------------------------->>>>>>>>>>>>>>>
--getDerivedStateFromProps(nextProps,prevState)-新的钩子,当父类接收到props并且调用到另一个渲染器之前调用
--getSnapshotBeforeUpdate(prevProps,prevState)-新的钩子,在render之后,在DOM中进行渲染之前调用
2.JSX是什么
JavaScript XML的简写,react使用的一种文件,它利用JavaScript的表现力和类似HTML的模板语法,这使得HTML文件非常容易理解,此文件能使应用非常可靠,并能够提高其性能,就是可以JS和XML写到同一文件
3.什么是展示组件?什么是容器组件
展示组件关心组件看起来是什么,专门通过props接受数据和回调,并且几乎不会有自身的状态,但当展示组件拥有自身的状态,通常也只关心UI状态而不是数据的状态(子组件)
容器组件则更关心组件是如何运作的,容器组件会为展示组件或者其他容器组件提供数据和行为,他们调用Flux actions,并将其作为回调提供给展示组件,容器组件经常是有状态的,因为他们是其他组件的数据源(父组件)
4.react中component与PrueComponent的区别
PrueComponent和Component几乎一样,对于PrueComponent而言,当其props或者state改变之时,新旧props与state将进行浅对比(shallow comparison),另一方,Component默认情况下其shouldComponentUpdate方法并不进行新旧props与state对比
5.react中key的重要性是什么
key作为识别唯一的Virtual DOM元素及其驱动UI的相应数据,它们通过回收DOM中当前所以的元素来帮助react优化渲染,这些可以必须唯一的数字或字符串,react只是重新排序元素而不是重新渲染它们,提高应用程序的性能
6.什么是有状态组件?什么是无状态组件
有状态组件它属于一个class类,有继承,可以通过this来接收状态和属性,有生命周期,无状态组件,他是一种函数式组件,没有state接收props渲染DOM, 并不关注其他逻辑
7.什么是ref
react支持一种非常特殊的属性ref,你可以绑定到render()输出的任何组件上,这个特殊的属性允许你引用render()返回相应的支撑实例,这样可以确保在任何时间总能拿到正确的实例
8.什么是高阶组件(HOC)
高阶组件就是重用组件逻辑的高阶方法,是一种源于react的组件模式,HOC是自定义组件,在它之内包含另一个组件,他们可以接受子组件提供的任何状态,但不会修改或复制其输入组件中的任何行为,你可以认为HOC是纯(prue)组件
高阶组件用途:
- 代码复用,逻辑抽象,抽离底层准备代码
- 渲染劫持
- 状态抽象和更改(控制)
- props更改
9.react hook是什么
hook是react1.6+的新特性,hook是允许从功能组件"挂钩"React状态和生命周期功能的功能
10.react组件之间是怎么通信的
父传子:利用props
子传父:利用props传入回调函数,或者redux等状态管理框架
跨级组件通信:使用context,或者redux等状态管理框架
11.redux什么,怎么使用
Redux是基于Flux设计模式的JavaScript应用成宿的可预测状态容器,如东县可以与react一起使用,也可以与任何其他视图库一起使用,它很小(约2kb)并且没有依赖性
核心原则:---三个基本原则
1.单个数据来源:整个应用程序的状态存储在单个对象树种,单状态树可以更容易追踪随时间变化并调试或检查应用程序
2.状态是只读的:改变状态唯一方法是发出一个动作,一个描述发生的事情的对象,这可以确保视图和网络请求都不会直接写入状态
3.使用纯函数进行更改:要指定状态树如何通过操作进行转换,编写reducers,reducers是纯函数,他将先前的状态和操作最为参数,并返回下一个状态
Store的角色是整个应用的数据存储中心,集中大部分页面需要的状态数据
ActionCreators ,view层与data层的介质
reduce,接收action并更新store
流程:用户通过界面组件,触发ActionCreators,携带store中的新state与action流向reducer,reducers返回新的state,并更新页面
使用方法:
例如reduce实现标签动态增减
1.创建基本项目,通过yarn add redux 安装redux npm 包(cnpm install -- save redux)
2,利用action函数创建相应的action,action.js 文件(action部分)
/**redux/actions.js文件代码**/
const ADD_TAG="TAG_ADD";
const DEL_TAG="TAG_DEL";
//新增标签Action
export const addTag=(payload)=>{
return {
type:ADD_TAG,
payload:payload
}
}
//移除标签Action
export const delTag=()=>{
return {
type:DEL_TAG
}
}
3.定义初始数据状态,state.js文件(state部分)
/**redux/state.js文件代码**/
export const InitTagState=[{
"id":"001",
"name":"标签一"
}];
4.使用纯函数创建reducer处理机,reducer.js文件(reducer部分)
/**redux/reducer.js文件代码**/
import {initTagState} from "./state";
import {ADD_TAG,DEL_TAG} from "./actions";
export const TagReducer=(state=initTagState,data)=>{
let new_arr=[];
new_arr=[].concat(state);
switch(data.type){
case ADD_TAG: //新增标签
new_arr.push(data.payload);
return new_arr;
case DEL_TAG: //删除标签
new_arr.splice(0,1);
return new_arr;
default:
return new_arr;
}
}
5.redux基本架构完成,然后将他们关联,形成概念化store,index.js文件
import {createStore,combineReducers} from "redux";
import {TagReducer} from "./reducer";
/*
* 多个reducer汇总的写法(注释区域)
* 需要用combineReducers方法关联形成一个大的reducer
* 只有一个就没有必要用combineReducers方法
*/
// const allReducers={
// tInfo:TagReducer,
// //...
// }
// const reducers=combineReducers(allReducers);
// const store=createStore(reducers);
/*单个写法*/
const store=createStore(TagReducer);
export default store;
6.通过subscribe方法(订阅store的变化,每次对store进行action,都会触发subscribe注册的函数调用),将redux与项目主入口index.js关联起来,根目录下index.js文件
/*根目录中index.js文件*/
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import store from "./redux";
const render=()=>{
ReactDOM.render(<App />, document.getElementById('root'));
};
render();
const unsubscribe=store.subscribe(()=>{
render();
});
serviceWorker.unregister();
7.组件功能实现文件App.js
import React, { Component } from 'react';
import store from "./redux";
import {addTag,delTag} from "./redux/actions";
import './App.css';
class App extends Component {
addTagFuns=()=>{
const obj={
"name":"标签二"
};
store.dispatch(addTag(obj));
}
delTagFuns=()=>{
store.dispatch(delTag());
}
render() {
const tag_list=store.getState();
let tag_com=tag_list.map((item)=>{
return (<span class="tag">{item.name}</span>);
})
return (
<div className="App">
<div>
<button type="button" onClick={this.addTagFuns}>新增标签</button>
<button type="button" onClick={this.delTagFuns}>删除标签</button>
</div>
{tag_com}
</div>
);
}
}
export default App;
12.react渲染原理和过程
因操作DOM元素会触发浏览器的回流和重绘,影响性能,所以减少操作dom就能提升性能,react会调用render()函数构建虚拟DOM树,当state/props改变时,react会再次调用render函数,构建一个新的虚拟DOM树,和旧的作对比,批量更新节点
13.react使用什么更新节点?原理和过程什么
主要使用diff算法,根据两个假设
1.两个相同的组件产生类似的DOM结构,不同组件产出不同DOM结构
2.对于同一层次的一组子节点,他们可以通过唯一Id区分
react的diff函数只对同层节点进行对比,即父节点相同会进行比对,因为不同组件的dom结构不同,所以没必要对比子节点
如果出现节点不同,会直接删除节点,重新新建节点
如果节点相同属性不同,则更新属性
14.简述react事件机制
react利用事件委托机制实现事件机制,事件并没有绑定在真实的dom节点上面,是绑定在最外层的document上,使用一个统一的监听器,所以的事件都由这个监听器统一分发
组件挂载更新时,会将事件分门别类放进事件池,事件触发根据event找到对应的组件,再组件标识和事件类型找到对应的事件进行监听回调,然后执行回调函数
15.fiber是什么
因为js的运数,页面布局和页面绘制等等都在浏览器的主线程,如果js占用浏览器主线程事件长会掉帧,所以重写reconciler层(组件生命周期和diff算法),命名为fiber Reconciler,建立了自己的组件调用栈,让diff计算可打断
16.什么是服务器渲染
服务器接到用户请求之后,计算用户需要的数据,然后将数据更新成视图。发给客户端,客户端直接将这字符串塞进页面即可
17.服务器渲染和浏览器渲染对比
服务器渲染:优点--页面相应比较好,用户体验好,对于搜索引擎比较友好
缺点--增加一层node.js增加服务器的计算,前后端分工不明,不利于开发