React18内核探秘:手写React高质量源码迈向高阶开发
download:https://www.sisuoit.com/4316.html
预备阶段-基层环境
装置node.js(官网下载即可)
node -v (检查是否装置node完结)
装置yarn新一代的包管理工具facebook开发,你也可以挑选cnpm
yarn的速度会比npm快
装置版别统一,更安全
更简洁的输出
更好的语义化
sudo cnpm install yarn -gyarn -v(检查是否装置yarn完结)
运用git在马云上进行托管,并在本地clone下来项目
git clone 你项意图地址cd 你的项目
装备gitignore(git命令忽视)
vim .gitignorei(修改命令).DS_Store(Mac自带)node_modules(node包)dist(打包的压缩文件)*.log(错误信息等)
初始化项目
yarninit/cnpminit
提交项目
gitadd.(保存到暂存区)git commit-m'补白信息'(把暂存区内容保存到分支)git pull(拉取其他分支代码)git push(将更新内容提交进入远程分支)
装置webpack打包工具(装备规矩检查webpack章节)
yarn add webpack--dev/cnpm install webpack--dev在根目录下创立一个webpack.config.js文件1.需求处理的文件类型 html=>html-webpack=plugin js es6=>babel+babel-preset-react css=>css-loader+sass-loader img=>url-loader+file-loader2.常用模块 html-webpack-plugin=>html独自打包成文件 extract-text-webpack-plugin=>款式打包成独自文件 CommonsChunkPlugin=>提出通用模块3.webpack-dev-server(1)为webpack项目提供web服务(2)更改代码主动改写,路径转发(3)yarn add webpack-dev-server--dev(4)解决多版别共存
1.装备webpack,在创立好的webpack.config.js中装备
增加模块输出口
constpath=require('path')module.exports={entry:'./src/app.js',output:{path:path.resolve(__dirname,'dist'),// __dirname代表根目录filename:'你想输出的文件姓名.js'}}
增加html插件
yarn add html-webpack-plugin--dev// 生成html5文件插件在webpack.config.js中设置constpath=require('path')constHtmlWebpackPlugin=require('html-webpack-plugin')// 引进插件module.exports={entry:'./src/app.js',output:{path:path.resolve(__dirname,'dist'),filename:'你想输出的文件姓名.js'},plugins:[// 运用插件newHtmlWebpackPlugin({template:'.src/index.html'// 引证模板自定义html文件,使打包出来的html与此文件共同})]}
增加babel插件 (将es6言语转换成es5)
yarn add babel-core@6.26.0babel-preset-env@1.6.1babel-loader@7.1.2--dev// 装置在webpack.config.js装备constpath=require('path')constHtmlWebpackPlugin=require('html-webpack-plugin')module.exports={entry:'./src/app.js',output:{path:path.resolve(__dirname,'dist'),filename:'app.js'},module:{rules:[{test:/\.js$/,exclude:/(node_modules)/,// 将不需求装换的文件夹扫除use:{loader:'babel-loader',options:{presets:['env']}}}]},plugins:[newHtmlWebpackPlugin({template:'.src/index.html'// 引证自定义html文件})// 生成html5文件]}
装置react的插件
yarn add babel-preset-react --dev / cnpm install babel-preset-react --dev
yarn add html-webpack-plugin--dev// 生成html5文件插件在webpack.config.js中设置constpath=require('path')constHtmlWebpackPlugin=require('html-webpack-plugin')// 引进插件module.exports={entry:'./src/app.js',output:{path:path.resolve(__dirname,'dist'),filename:'你想输出的文件姓名.js'},plugins:[// 运用插件newHtmlWebpackPlugin({template:'.src/index.html'// 引证模板自定义html文件,使打包出来的html与此文件共同})]}
增加babel插件 (将es6言语转换成es5)
yarn add babel-core@6.26.0babel-preset-env@1.6.1babel-loader@7.1.2--dev// 装置在webpack.config.js装备constpath=require('path')constHtmlWebpackPlugin=require('html-webpack-plugin')module.exports={entry:'./src/app.js',output:{path:path.resolve(__dirname,'dist'),filename:'app.js'},module:{rules:[{test:/\.js$/,exclude:/(node_modules)/,// 将不需求装换的文件夹扫除use:{loader:'babel-loader',options:{presets:['env','react']// 只需求在这儿引证react}}}]},plugins:[newHtmlWebpackPlugin({template:'.src/index.html'// 引证自定义html文件})// 生成html5文件]}
装置款式的插件
>装置cssyarn add style-loader@0.19.1css-loader@0.28.8--dev在项目src中新建一个index.css页面,并在app.jsx中引进页面importReactfrom'react'importReactDOMfrom'react-dom'import'./index.css'装置webpack打包css成独立文件的插件yarn add extract-text-webpack-plugin@3.0.2--dev在webpack.config.js中更改对css的装备装备引进constExtractTextPlugin=require('extract-text-webpack-plugin'){test:/\.css$/,use:ExtractTextPlugin.extract({// 这儿改动fallback:'style-loader',use:'css-loader'})}由于这是一个插件,需求在plugin中装备>装置sassyarn add sass-loader--devyarn add node-sass--dev在webpack.config.js中rules css装备下增加{test:/\.scss$/,use:ExtractTextPlugin.extract({fallback:'style-loader',use:['css-loader','sass-loader']})}
对图片的处理
yarn add url-loader --sev
在webpack.config.js中装备{test: /\.(png|jpg|gif)$/,
use: [{loader: 'url-loader',
options:{limit:8192 // 文件大于8k被作为文件}}]}
对字体图标的处理
yarn add font-awesome{test: /\.(eot|svg|ttf|woff|woff2|otf)$/,
use: [{loader: 'url-loader',
options:{limit:8192 // 文件大于8k被作为文件}}]}
对公共模块的处理
在plugin中处理
constpath=require('path')constwebpack=require('webpack')//为了引证webpack自带办法constHtmlWebpackPlugin=require('html-webpack-plugin')constExtractTextPlugin=require('extract-text-webpack-plugin')module.exports={entry:'./src/app.jsx',output:{path:path.resolve(__dirname,'dist'),filename:'js/app.js'},module:{rules:[{test:/\.jsx$/,exclude:/(node_modules)/,// 将不需求装换的文件夹扫除use:{loader:'babel-loader',options:{presets:['env','react']// 主动根据环境打包}}},{test:/\.css$/,use:ExtractTextPlugin.extract({fallback:'style-loader',use:['css-loader']})},{test:/\.scss$/,use:ExtractTextPlugin.extract({fallback:'style-loader',use:['css-loader','sass-loader']})},{test:/\.(png|jpg|gif|jpeg)$/,use:[{loader:'url-loader',options:{limit:8192,// 文件大于8k被作为文件name:'resource/[name].[ext]'}}]},{test:/\.(eot|svg|ttf|woff|woff2|otf)$/,use:[{loader:'url-loader',options:{limit:8192,// 文件大于8k被作为文件name:'resource/[name].[ext]'}}]}]},plugins:[newHtmlWebpackPlugin({template:'./src/index.html'// 引证自定义html文件}),// 生成html5文件newExtractTextPlugin('css/[name].css'),// 将款式独自打包出来生成新的css页面// 提出公共模块,webpack自带newwebpack.optimize.CommonsChunkPlugin({name:'common',// 手动指定的通用木块filename:'js/base.js'})]}
webpack 主动改写处理webpack-dev-server
yarn add webpack-dev-server
在config下与plugin同级加上
devServer:{}为了防止打包后的图片在根目录下找不到
output:{path:path.resolve(__dirname,'dist'),publicPath:'/dist/',//在这儿增加路径filename:'js/app.js'},编译打包就用webpack-dev-server就可以了
运用react环境搭建项目
yarn add react react-dom 在app.js中引证react结构,并将app.js的后缀更改为jsx,webpack.config.js中的js装备也要变成jsx,进口文件的js也要更改为jsximportReactfrom'react'importReactDOMfrom'react-dom'
package.json的装备
"scripts": { "dev": "node_modules/.bin/webpack-dev-server", "dist": "node_modules/.bin/webpack -p" },
这样就可以运用yarn dev发动项目
yarn dist 打包项目
react正式开始咯(上诉办法均为自己手打搭建一个react项目,了解每一步,接下来是react提供的项目创立办法)
react => 视图层结构 组件化 JSX表达式 虚拟DOM
Facebook 开源的一个JavaScript库
React结合生态库构成一个MVC结构(vue也是mvc)
特色:Declarative(声明式编码:只需求声明在哪里做什么,无需关心如何实现);Component-Based(组件化编码);高效-高效的DOM Diff算法,最小化页面重绘
单向数据流
生态介绍
vue生态:vue + vue-router + vuex + axios + babel + webpack
react生态: react + react-router + redux + axios + babel + webpack
项意图创立(另一种方法,但是本人喜爱上面的手动装备,看得懂)
yarnadd/cnpm installglobal/-g create-react-app(大局装置)在作业区创立项目 create-react-app 你的项目称号 cd 你的项目称号 cnpm/yarn start 发动
JSX语法
增加html
letjsx=
thisisa jsx programmer
ReactDOM.render(jsx,// 将jsx组件放到烘托的dom下document.getElementById('app))
增加款式
行内款式letstyle={color:'red'}letjsx=
引进class款式在index.scss中设置body{.jsx{font-size:16px;}}letjsx=
// react中运用className引证款式称号
增加逻辑
(1)运用变量
letname="pig"letjsx=
I am a {pig}
ReactDom.render(jsx,document.getElementById('app'))
(2)条件判别
lettruth=trueletjsx=(//加括号的意图是为了换行的时候,修改器不会给我们主动填补分号
{// 条件判别需求加上{}truth?
I am a pig
:
I am not a pig
}
)
(3)jsx中刺进注释
{/*我是一个注释*/}
(4)数组的运用
letnames=['pig','dog','chicken']letjsx=({names.map((name,index)=>I am {name}
)})
增加组件
(1)基础
functionComponent(){return
I am a pig
}ReactDom.render(,// 如果是变量直接饮用,如果是组件需求加上标签document.getElementById('app'))
(2)es6组件写法
classES6ComponentextendsReact.Component{render(){return
I am a pig in es6
}}ReactDom.render(
// 两个组件共存需求包裹在一个div中
,
document.getElementById('app')
)
(3)组件初始化变量
classComponentextendsReact.Component{constructor(props){super(props);this.state={name:'pig'}}render(){return
I am a {this.state.pig}
}}
(4)更改组件初始化变量
classComponentextendsReact.Component{constructor(props){// props在子组件中只能被运用不能被改动super(props);this.state={name:'pig'}}render(){setTimeOut(()=>{this.setState({name:'Pi g Pig'})},2000)return
I am a {this.state.pig}
}}
(5)父组件传值
classComponentextendsReact.Component{constructor(props){super(props)}render(){return
I am a {this.props.name}
}}ReactDom.render(,docuement.getElementById('app'))
(6)组件增加点击事情(办法一)
classComponent extends React.Component{constructor(props){super(props);this.state={age:18}this.addAge=this.addAge.bind(this)}addAge(){this.setState({age:this.state.age+1})}render(){return(
I am{this.state.age}years old
)}}ReactDom.render(,docuement.getElementById('app'))
(7)组件增加点击事情(办法二)
classComponentextendsReact.Component{constructor(props){super(props);this.state={age:18}}addAge(){this.setState({age:this.state.age+1})}render(){return(
I am {this.state.age} years old
{this.addAge(e)}}>
)
}
}
ReactDom.render(
,
docuement.getElementById('app')
)
(8)组件增加输入框更改事情
classComponentextendsReact.Component{constructor(props){super(props);this.state={age:18}}changeValue(e){this.setState({age:e.target.value})}render(){return(
I am {this.state.age} years old
{this.changeValue(e)}}/>
)}}ReactDom.render(,docuement.getElementById('app'))
(9)容器性组件嵌套组件
classComponent extends React.Component{constructor(props){super(props);this.state={age:18}}changeValue(e){this.setState({age:e.target.value})}render(){return(
I am{this.state.age}years old
{this.changeValue(e)}}/>
)}}classTitle extends React.Component{constuctor(props){super(props)}render(props){return
{this.props.title}
}}classApp extends React.Component{render(){return(
// 在这儿引证小组件component
)}}ReactDom.render(,// 这儿换成Appdocuement.getElementById('app'))
(10)组件嵌套组件
classComponentextendsReact.Component{constructor(props){super(props);this.state={age:18}}changeValue(e){this.setState({age:e.target.value})}render(){return(
I am {this.state.age} years old
{this.changeValue(e)}}/>
)}}classAppextendsReact.Component{render(){return(
app
// 在这儿引证小组件component
)}}ReactDom.render(,// 这儿换成Appdocuement.getElementById('app'))
(11)容器性组件嵌套组件,传值可以为任何html方法
classComponent extends React.Component{constructor(props){super(props);this.state={age:18}}changeValue(e){this.setState({age:e.target.value})}render(){return(
I am{this.state.age}years old
{this.changeValue(e)}}/>
)}}classTitle extends React.Component{constuctor(props){super(props)}render(props){return
{this.props.children}
// 这儿变成获取子children}}classApp extends React.Component{render(){return(
我是spanspanlink//更改为html方法
)}}ReactDom.render(,// 这儿换成Appdocuement.getElementById('app'))
(12)子组件给父组件传值
classFather extends React.Component{constructor(props){super(props);this.state={bgColor:'red'}}changeMyBgColors(color){this.setState({bgColor:color})}render(){return(
我是爸爸
{this.changeMyBgColors(color)}}/>
)}}classChild extends React.Component{constructor(props){super(props)}changeMyBgColor(){this.props.changeColor('blue')}render(){return(
我是baby
{this.changeMyBgColor(e)}}>我想改动我爸爸的背景颜色
)}}ReactDOM.render(,document.getElementById('app'))
(13)兄弟之间的组件通讯(子1传父,父在传子2)
classChild1extendsReact.Component{constructor(props){super(props)this.state={color1:'red'}}changeMyBrotherColor(props){this.props.change2Color(this.state.color1)}render(){return(
我是孩子1
{this.changeMyBrotherColor(e)}}>我要改动我弟弟的颜色咯
)}}classChild2extendsReact.Component{constructor(props){super(props)}render(){return(
我是孩子2
)}}classFatherextendsReact.Component{constructor(props){super(props)this.state={color2:'yellow'}}changColor(colorsss){this.setState({color2:colorsss})}render(){return(
这是我的孩子们
{this.changColor(color)}}/>
)}}ReactDOM.render(,document.getElementById('app'))
react生命周期
getDefaultProps // 初始化props特点,props来自其他组件
getInitialState // 初始化组件的状况
componentWillMount // 组件加载之前
render // 烘托
componentDidMount // 组件dom刺进之后
componentWillReceiveProps // 承受父组件的传递
shouldComponentUpdate // 组件的更新处罚
componentWillUpdate // 组件要更新前
componentDidUpdate // 组件更新后
componentWillUnmount // 组件的销毁
Mounting : 挂载阶段
Updating: 运行时阶段
Unmounting: 卸载阶段
Error Handling: 错误处理
importReactfrom'react'importReactDOMfrom'react-dom'import'./index.scss'classChildextendsReact.Component{// 结构函数constructor(props){super(props)this.state={data:'oldzhuzhu'}console.log('这儿是初始化数据constructor')}componentWillMount(){// 组件烘托前console.log('componentWillMount')}componentDidMount(){// 组件烘托完毕console.log('componentDidMount')}componentWillReceiveProps(){// 即将承受父组件传来的props触发console.log('componentWillReceiveProps')}shouldComponentUpdate(){// 子组件是不是应该更新console.log('shouldComponentUpdate')returntrue// 如果是false,后面的update就不会跟着更新}componentWillUpdate(){// 组件即将更新console.log('componentWillUpdate')}componentDidUpdate(){// 组件更新完结console.log('componentDidUpdate')}componentWillUnmount(){// 组件即将销毁调用console.log('componentWillUnmount')}// 点击事情handleClick(){console.log('这儿是更新数组')this.setState({data:'zhuzhuzhu'})}// 烘托render(){console.log('render')return(
{this.state.data} 接收到的props: {this.props.data} {this.handleClick()}}>更新组件
)}}classFatherextendsReact.Component{constructor(props){super(props)this.state={data:'old props'}}changeData(){this.setState({data:'new props',show:true})}byeChild(){this.setState({show:false})}render(){return(
{this.state.show?:null} {this.changeData()}}>改动子组件的props {this.byeChild()}}>
)}}ReactDOM.render(,document.getElementById('app'))
按次序输出值:
constructor// 结构函数初始化componentWillMount// 组件烘托前render// 组价烘托componentDidMount// 选件烘托完结componentWillReceiveProps// 子组件接收到父组件传来的propsshouldComponentUpdate// 是否组件进行更新,true更新,false接下来的周期不触发componentWillUpdate// 组件更新前render// 更新componentDidUpdate// 组件更新完毕componentWillUnmount// 组件被摧毁之前
react-router
1.router几种方法
页面路由
window.location.href='地址'// www.baidu.comhistory.back()//回退
hash 路由
window.location='#hash'window.onhashchange=function(){console.log('current hash'+window.location.hash)}
h5路由
history.pushState('name','title','/path')// 推进一个状况history.replaceState('name','title','/path')// 替换一个状况window.onpopstate=function(){console.log(window.location.href)console.log(window.location.pathname)console.log(window.location.hash)console.log(window.location.search)}
2. react-router几种方法
hash
importReactfrom'react'importReactDOMfrom'react-dom'import{HashRouterasRouter,Route,Link}from'react-router-dom'// 这儿是Hashimport'./index.scss'classAextendsReact.Component{constructor(props){super(props)}render(){return(
Component A
)}}classBextendsReact.Component{constructor(props){super(props)}render(){return(
Component B
)}}classWrapperextendsReact.Component{constructor(props){super(props)}render(){return(
组件A
组件B {this.props.children}
)}}ReactDOM.render( ,document.getElementById('app'))