三大框架的区别:
Angular带有比较强的排它性的
React主张是函数式编程的理念,侵入性没有Angular那么强,主要因为它是软性侵入。
Vue 渐进式的
react与vue的对比 可以从redux和vuex中对比
你如何看待react /什么是react react就是一个框架 他相对于mvc来说只是其中的v 他适用于开发数据不断变化的大型应用程序
react相对其他框架优势: 高性能高效率 实现了前端界面的高性能高效率开发,所以说react很擅长处理组件化的页面
1.虚拟dom
虚拟DOM是在DOM的基础上建立了一个抽象层,对数据和状态所做的任何改动,都会被自动且高效的同步到虚拟DOM,最后再批量同步到DOM中。
是一个JavaScript对象,重新渲染的时候,会对比这一次产生的Virtual DOM和上一次渲染的Virtual DOM,对比发现差异之后,只需修改真正的DOM树时就只需要触及差别中的部分就行,使用这个虚拟dom,避免对原生dom的创建和对比,这样就大大提升了性能,因为原生dom的创建是非常 消耗性能的,而对js对象的对比和创建对性能开销很小,从这种方式来提供应用的性能
2.组件
组件化 组件指的就是同时包含了html、css、js、image元素的聚合体
每个组件和组件都相互独立 便于维护
组件是通过React.createClass创建的(ES5),在es6中直接通过class关键字来创建
组件的划分要满足高内聚,低耦合的原则。
高内聚是指把逻辑紧密相关的内容放在一个组件中。
低耦合指的是不同组件的依赖关系要尽量弱化,每个组件要尽量独立。
组件其实就是一个构造器,每次使用组件都相当于在实例化组件
react的组件必须使用render函数来创建组件的虚拟dom结构
组件需要使用ReactDOM.render方法将其挂载在某一个节点上
组件的首字母必须大写
3.单向数据流 数据绑定 父到子
4.jsx树
通常我们输出节点的时候都是map一个数组然后返回一个ReactNode,为了方便react内部进行优化,我们必须给每一个reactNode添加key,这个key prop在设计值处不是给开发者用的,而是给react用的,大概的作用就是给每一个reactNode添加一个身份标识,方便react进行识别,在重渲染过程中,如果key一样,若组件属性有所变化,则react只更新组件对应的属性;没有变化则不更新,如果key不一样,则react先销毁该组件,然后重新创建该组件。
主要是因为react是基于虚拟dom跟diff算法提高性能的,而提高性能意味着会做一些dom节点的复用,key就是负辅助diff算法的,在某些情况下用index是没问题的,例如只是循环渲染展示,但是如果有涉及中间节点的增删的操作,这样就会造成react无法正确识别哪些节点是删的,哪些节点是增加的,会发生很多看似奇怪的现象
优化react性能的时候,对于太多深层嵌套的组件,由于父组件的state改变会导致包括子组件也重新render可以根据情况使用纯函数组件,由于纯函数组件是没有状态的组件这个时候可以用高阶组件给函数组件封装一个类似PureComponet的功能
对于性能优化 还可以使用React.memo
React.memo
是 React 16.6 新的一个 API,用来缓存组件的渲染,避免不必要的更新,其实也是一个高阶组件,与 PureComponent
十分类似,但不同的是, React.memo
只能用于函数组件 。
import { memo } from 'react';
function Button(props) {
// Component code
}
export default memo(Button);
高级用法
默认情况下其只会对 props 做浅层对比,遇到层级比较深的复杂对象时,表示力不从心了。对于特定的业务场景,可能需要类似 shouldComponentUpdate
这样的 API,这时通过 memo
的第二个参数来实现:
function arePropsEqual(prevProps, nextProps) {
// your code
return prevProps === nextProps;
}
export default memo(Button, arePropsEqual);
注意:与 shouldComponentUpdate
不同的是,arePropsEqual
返回 true
时,不会触发 render,如果返回 false
,则会。而 shouldComponentUpdate
刚好与其相反。
Router组件身上有history,
Route组件为里面的路由组件传递了location和match,
Router组件为路由组件传递了history
可以在view层里面的生命周期里面监听路由 进行相应的操作
1. 渲染根组件的时候,最外层包裹上Router组件,在其上可以设置history属性,值可以是hashHistory||browserHistory
当值为hashHistory的时候,url的变化为hash值的变化,router会去检测hash变化来实现组件的切换
当值为browserHistory的时候,url的变化为path的变化,需要后端进行配置
2. 在需要切换路由组件的地方,通过this.props.children来表示对应路由组件
3. 在Route中可以多次嵌套Route来实现多级路由
4. 使用Redirect组件可以做到从一个路由马上重定向到其他路由,利用这样的属性,当我们form设置为'*'的时候,就可以将匹配不到的路由重定向到某路由下
4. 可以在配置Route的时候给path里加入/:param 才表示此路由需要参数
传入的时候,querystring参数可以在Link里的query中传入和设置,在目标组件中,通过this.props中的,params、routePrams、location等来接收参数
5. 编程式导航
* 在路由组件中通过this.props.history获取到history对象,利用里面push、replace、go、goBack方法来进行隐式跳转
* 可以从react-router中引入browserHistory或者hashHistory调用里面的push、replace、go、goBack方法来进行隐式跳转
6. 可以通过在路由配置上设置 onLeave和onEnter路由钩子来监听路由的变化
router3 4 区别
1)在V3中,一般使用,只是在其history属性中指定是哪种实现: hashHistory或者browserHistory之类的。而在v4中,你需要直接用具体的实现,比如HashRouter或者BrowserRouter:
(2)在V3中,嵌套Route和Index Route的使用是很常见的。在 v4 中 IndexRoute没了,然后不允许Route嵌套。
(3)在 v3 中,Router 的定义一般是全局的,所有的路由都在一个文件中定义;而在 v4 中Router可以出现在任何组件中。
(4)在 v3 中,你可以从params这个属性中取到URL 中传递过来的参数。比如我在 BlogLayout中获取bloggerID,这个属性在v4中不再被自动注入了,需要从match属性中获取。
(5)在v3中,我可以使用使用 Route的 onEnter, onUpdate和 onLeave事件来做一些事情。在v4中,Route的事件没了。解决的办法是使用withRouter 这个HOC (高阶组件)
react-redux将所有的组件分为两大类 把Provider放在最外面并传入store connect进行连接
UI 组件有以下几个特征。
* 只负责 UI 的呈现,不带有任何业务逻辑
* 没有状态(即不使用this.state这个变量)
* 所有数据都由参数(this.props)提供
* 不使用任何 Redux 的 API
容器组件的特征恰恰相反。
* 负责管理数据和业务逻辑,不负责 UI 的呈现
* 带有内部状态
* 使用 Redux 的 API
只要记住一句话就可以了:UI 组件负责 UI 的呈现,容器组件负责管理数据和逻辑。
connect()能生成一个高阶组件,高阶组件接收一个UI组件之后能生成一个新的容器组件
* Provider Provider就是把我们用rudux创建的store传递到内部的其他组件。让内部组件可以享有这个store并提供对state的更新。
他是通过使用context树来实现的,将store放到context树上,然后内部的所有的容器组件在通过this.context.store来使用到context树上的store
* connect是一个函数,这个函数接收到mapStateToProps、mapDispatchToProps属性,connect会返回一个高阶组件,在这个高阶组件中接收UI组件,返回一个新组件就是容器组件,因为有闭包的特性,所以容器组件可以使用到connect中传入的mapStateToProps、mapDispatchToProps属性,然后容器组件可以从context树中取出Provider放入的store,然后利用mapStateToProps、mapDispatchToProps将状态和调用dispatch的方法传入给UI组件,当store数据变化的时候,容器组件会rerender,重新给UI组件传入最新的状态
dispatch的作用 中间件的作用就是让actionCreator的方法能返回一个可以接收到dispatch的函数,在这个函数里就可以做一些异步的操作了
缺点:一个组件的所有数据都必须由父组件传过去,当一个组件相关数据更新时,及时父元素不需要用到这个组件的,父组件还是会重新render,可能会有效率的影响。
需要使用redux的项目:
* 某个组件的状态,需要共享
* 某个状态需要在任何地方都可以拿到
* 一个组件需要改变全局状态
* 一个组件需要改变另一个组件的状态
步骤:
通过createStore来创建store,并为其绑定reducer
reducer每次都能返回一个新的数据,同步到store的状态上
在视图中通过store.getState()来获取到状态
当想要更新数据的时候,也就是用户产生了操作,调用actionCreator的方法生成action传入到reducer中
reducer返回一个新状态,store的state被reducer更改为新state的时候,store.subscribe方法里的回调函数会执行(生命周期里执行),此时就可以通知view去重新获取state
> 注意:redux都不是必须和react搭配使用的,因为flux和redux是完整的架构,在react中,只是将react的组件作为redux中的视图层去使用了。
划分reducer
因为一个应用中只能有一个大的state,这样的话reducer中的代码将会特别特别的多,那么就可以使用combineReducers方法将已经分开的reducer合并到一起
applyMiddleware(thunk)//使用中间件
在这里这个中间件的作用就是让actionCreator的方法能返回一个可以接收到dispatch的函数,在这个函数里
就可以做一些异步的操作了
#####初始化阶段
1. 实例化组件之后,组件的getDefaultProps钩子函数会执行
这个钩子函数的目的是为组件的实例挂载默认的属性
这个钩子函数只会执行一次,
2. 执行getInitialState为实例挂载初始状态,且每次实例化都会执行,也就是说,每一个组件实例都拥有自己独立的状态呢
3. 执行componentWillMount,这里是在渲染之前最后一次更改数据的机会,在这里更改的话是不会触发render的重新执行
4. 执行render,渲染dom
5. 执行componentDidMount ,多用于操作真实dom。ajax请求,初始化数据的获取
componentDidMount方法中的代码,是在组件已经完全挂载到网页上才会调用被执行,所以可以保证数据的加载。此外,在这方法中调用setState方法,会触发重渲染。所以,官方设计这个方法就是用来加载外部数据用的
##### 运行中阶段
1. componentWillReceiveProps
这个函数不是props变化的时候才会渲染,而是当父组件传入新的props,才会触发
一般用来对比prop和state并更新state
!!! 尽量不要在 componentWillReviceProps 里使用 setState,如果一定要使用,那么需要判断结束条件,不然会出现无限重渲染,导致页面崩溃。
2. 接下来就会执行shouldComponentUpdate,这个函数的作用:
接收nextProp、nextState,根据根据新属性状态和原属性状态作出对比、判断后控制是否更新
提高性能,返回true就更新,否则不更新,默认返回true
3. componentWillUpdate,在这里,组件马上就要重新render了,多做一些准备工作,千万千万,不要在这里修改状态,否则会死循环
4. render,重新渲染dom
5. componentDidUpdate,在这里,新的dom结构已经诞生了,在这里可以操作到更新完成后的dom了
##### 销毁阶段
当组件被销毁之前的一刹那,会触发componentWillUnmount,
做一些善后工作 比如说你切换路由的时候 上一个路由还在请求数据 但是你已经销毁了那个组件 这个时候就会警告你不能对已经已经销毁的组件获取数据 ,所以就可以设置一个开关 当销毁的时候停止获取数据
##### 更新阶段的生命周期
componentWillReceiveProps(object nextProps)
:当挂载的组件接收到新的props时被调用。此方法应该被用于比较this.props 和 nextProps以用于使用this.setState()执行状态转换。(组件内部数据有变化,使用state,但是在更新阶段又要在props改变的时候改变state,则在这个生命周期里面)
shouldComponentUpdate(object nextProps, object nextState)
: -boolean 当组件决定任何改变是否要更新到DOM时被调用。作为一个优化
实现比较this.props 和 nextProps 、this.state 和 nextState ,如果React应该跳过更新,返回false。
componentWillUpdate(object nextProps, object nextState)
:在更新发生前被立即调用。你不能在此调用this.setState()
。
componentDidUpdate(object prevProps, object prevState)
: 在更新发生后被立即调用。(可以在DOM更新完之后,做一些收尾的工作)
高阶组件是一个函数,接收一个不是路由的组件再返回一个新组件,这样就可以给新组件上添加一些api了,实现代码复用
无状态组件:
function Faaa(props){
return (
)
}
react怎么从虚拟dom中拿出真实dom?(ref)
// react怎么从虚拟dom中拿出真实dom?(ref)
var MyComponent = React.createClass({
handleClick: function() {
this.refs.myTextInput.focus();
},
render: function() {
return (
);
}
});
{...this.props}
(不要滥用,请只传递component需要的props,传得太多,或者层次传得太深,都会加重shouldComponentUpdate里面的数据比较负担,因此,请慎用spread attributes(
::this.handleChange()
。(请将方法的bind一律置于constructor)
this.handleChange.bind(this,id)
复杂的页面不要在一个组件里面写完。
请尽量使用const element
。
map里面添加key,并且key不要使用index(可变的)。
尽量少用setTimeOut
或不可控的refs、DOM操作。
props
和state
的数据尽可能简单明了,扁平化。
使用return null
而不是CSS的display:none
来控制节点的显示隐藏。保证同一时间页面的DOM节点尽可能的少。
this.props对象的属性与组件的属性一一对应,但是有一个例外,就是this.props.children
属性。它表示组件的所有子节点。
这里需要注意,this.props.children
的值有三种可能:如果当前组件没有子节点,它就是undefined
;如果有一个子节点,数据类型是Object
;如果有多个子节点,数据类型就是array
。所以,处理this.props.children
的时候要小心。
React提供一个工具方法React.Children
来处理this.props.children
。我们可以用React.Children.map
来遍历子节点,而不用担心this.props.children
的数据类型是undefined
还是object
。
redux/react-redux/redux-thunk
node-sass/sass-loader
axios
babel-loader 进行转码
css-loader 对 css 文件进行打包
style-loader 将样式添加进 DOM 中
url-loader图片自动转成base64编码的
正好最近在做webpack构建优化和性能优化的事儿,插件请见webpack插件归纳总结。
构建优化:
减少编译体积 ContextReplacementPugin、IgnorePlugin、babel-plugin-import、babel-plugin-transform-runtime
并行编译 happypack、thread-loader、uglifyjsWebpackPlugin开启并行
缓存 cache-loader、hard-source-webpack-plugin、uglifyjsWebpackPlugin开启缓存、babel-loader开启缓存
预编译 dllWebpackPlugin && DllReferencePlugin、auto-dll-webapck-plugin
性能优化:
减少编译体积 Tree-shaking、Scope Hositing
hash缓存 webpack-md5-plugin
拆包 splitChunksPlugin、import()、require.ensure
搭建react脚手架
npm install -g create-react-app 全局安装脚手架
npm install -g yarn 全局安装yarn
create-react-app project 创建project项目
cd project 进project项目
yarn start 运行项目
yarn remove xxx 等同于 npm uninstall xxx —save 卸载指定包
yarn add sass-loader node-sass --save-dev 安装sass及配置(现在的新版webpack应该是自动配置sass了)
https://www.cnblogs.com/ye-hcj/p/7753085.html
yarn add redux --save 安装redux
yarn add react-redux --save 安装react-redux
yarn add react-router-dom --save 安装router
yarn add redux-thunk --save 安装react-thunk
yarn add antd-mobile --save
关于文件打包路径问题
解决办法:在package.json配置文件中加一句:"homepage": ".",
function ActionLink() {
function handleClick(e) {
e.preventDefault(); // 阻止冒泡
console.log('The link was clicked.');
}
return (
Click me
);
}
添加onClick事件时 需要在constructor里面bindthis
event.preventDefault(); 取消事件默认动作
react props 只读
通过this.textInput = React.createRef() 创建ref
this.textInput.current.focus(); 取得dom节点
绑定ref
antd 配置按需加载 在config文件里面
plugins: [
[
require.resolve('babel-plugin-named-asset-import'),
{
loaderMap: {
svg: {
ReactComponent: '@svgr/webpack?-prettier,-svgo![path]',
},
},
},
],
['import', { libraryName: "antd", style: 'css' }] // 按需加载
],