本节将开启React框架进阶学习第四篇
如果还没有学习 1-1 ~ 1-6 React框架基础的话,建议点我开始React框架基础学习
文章系列(React框架进阶)
2-1、React框架组件化state的使用
2-2、React函数组件、默认props
2-3、React使用props以及state、React生命周期localStorage的使用
大家好,我是Counterrr
不忘初心,砥砺前行
本文目录
一、React脚手架的使用
二、React组件模块构建
1、React脚手架的使用:
好的,在之前的项目,我们都是通过引入react的cdn并且开了live-server服务以及babel将jsx语法以及es6转为es5的语法,今天我们要来接触下react的脚手架工具,那我们如果学习过vue的话,应该很清楚,我们安装了vue-cli通过命令npm install -g @vue/cli去安装了vue-cli的全局命令,那么全局就会多了一个vue这个命令,这个是安装在全局上的。
而我们现在安装命令都是最好内置在文件夹里面,这是为什么呢?
安装在自己电脑全局命令,当我们把项目给别人去看时,别人的电脑没有这个全局命令,又要去安装是很麻烦的,最好是内置在文件里,这样在文件下就有这个命令,就不用去安装。
好的,那么我们看看react脚手架怎么去使用,我们可以点击这里进行查看。我们可以看到官网有这么一句话:
(npx 来自 npm 5.2+ 或更高版本, 查看 npm 旧版本的说明)
所以我们的npm版本要大于等于5.2+,所以我们打开命令行工具输入npm -v,查看当前npm的版本:
我们可以看到我们的版本比5.2+高就可以了,如果小于5.2的怎么办,那么我们可以输入这个命令去升级:
npm install npm -g
好的,接下来,我们在命令行里cd到桌面上进行创建react脚手架,并且使用命令:
npx create-react-app my-app
去构建my-app项目,只不过这个项目跟我们以前用cdn引入的方式不同,它是集成了我们webpack的环境,并且内置到react脚手架上,这样我们就省去了学习webpack的学习成本,直接去使用我们的脚手架就可以了。
如图所示,即为成功:
接着我们在桌面把my-app这个文件夹拖到vscode编辑器里,我们打开package.json,看到scripts下有启动命令start,具体如图:
然后点击Terminal打开终端,运行命令npm run start,它就会自动打开网页,页面如下:
说明我们脚手架工具创建的项目是没问题的。以后我们就会用这个去真实的去完成我们实际开发过程的项目。
2、React组件模块构建:
好的,我们使用react脚手架工具创建了我们my-app项目,总要做点什么吧,对了我们之前写的小项目,虽然重构成了组件化的开发,但是都是写在入口文件index.js下的,我们可以将它拿来模块化组件开发重构,这样每个组件就是一个模块,就比较清晰,首先我们删除src文件夹下的所有东西。接着我们在src文件夹新建一个index.js这就是一个入口文件。我们将之前写的小项目代码复制黏贴进去或者去我的2-3、React使用props以及state、React生命周期localStorage的使用这篇博文复制黏贴,在最后给出了代码。保存,发现报错:
这是为什么呢?因为之前是通过cdn的引入方式,这次是通过react脚手架工具的方式,所以会在全局有React和ReactDOM,只不过我们现在是在脚手架工具里,就可以使用es6的模块导入语法,在index.js文件上最开头加上如下代码:
import React from 'react'
import ReactDOM from 'react-dom'
一保存,看到又报错:
我们打开public文件夹下的index.html:

发现它这边的id为root,那么我们把这个id改成app,因为我们以前采用cdn的方式,就是去渲染id为app的dom节点。好的一保存,发现页面还是我们熟悉的,我们去跑一下如下:
好的看见项目还是一如既往的跑起来了,只不过这次是采用react的脚手架工具,以后都会采用脚手架的工具进行开发。
接下来我们给每个组件进行模块化的重构。
首先在src文件夹下新建components文件夹,接着创建MySelectLanApp.js,将index.js下的所有代码剪切下来放到MySelectLanApp.js下,再在components文件夹下创建Header.js,将MySelectLanApp.js下的:
const Header = (props) => {
return (<header>
<div>{props.obj.title}</div>
<div>{props.obj.des}</div>
<div>{props.obj.tips}</div>
</header>
)
}
Header.defaultProps = {
obj: {
title: '今天学习了吗?',
des: '大家好,我爱撸码。',
tips: '如果学不死就往死里学。'
}
}
这两段代码给剪切下来放到Header.js我们就给它按照这样模块化。并且在Header.js引入import React from 'react'因为jsx编译需要依赖react.creatElement()这个函数,然后在后面给它用es6模块暴露出去的语法export default Header将它暴露出去。接着在MySelectLanApp.js中用import Header from './Header''去引入这个Header.js,然后删除MySelectLanApp.js中的ReactDOM.render(<MySelectLanApp/>, document.getElementById('app')),并且在最后使用export default MySelectLanApp将这个模块给暴露出去,然后src文件夹下的index.html增加代码:
import ReactDOM from 'react-dom'
import React from 'react'
import MySelectLanApp from './components/MySelectLanApp'
ReactDOM.render(<MySelectLanApp/>, document.getElementById('app'))
看到我们的项目还是一如既往的跑起来,接下来我们将每个组件都按照上面说的方法去模块化。
好的最后给出src文件夹目录结构:
src
├── components
│ ├── AddLang.js
│ ├── ButtonActive.js
│ ├── Header.js
│ ├── MySelectLanApp.js
│ ├── Option.js
│ └── Options.js
├── index.js
└── tree.md
可以看到我们把所有组件都模块化了。最后给出代码,index.js中的代码如下:
import ReactDOM from 'react-dom'
import React from 'react'
import MySelectLanApp from './components/MySelectLanApp'
ReactDOM.render(<MySelectLanApp/>, document.getElementById('app'))
AddLang.js中的代码如下:
import React from 'react'
class AddLang extends React.Component {
constructor(props) {
super(props)
this.submitFunc = this.submitFunc.bind(this)
}
submitFunc (e) {
e.preventDefault();
let value = e.target.elements.languages.value;
if (value == '') {
alert('请输入!');
}
else {
this.props.valueHandler(value);
e.target.elements.languages.value = '';
}
}
render () {
return (<form onSubmit={this.submitFunc}>
<div>
<input type="text" name="languages"></input>
<button>添加语言</button>
</div>
</form>)
}
}
export default AddLang
ButtonActive.js代码如下:
import React from 'react'
const ButtonActive = (props) => {
return (<div>
<button onClick={props.removeAllFunc}>清除</button>
<button disabled={props.isDisabled} onClick={props.selectLanFunc}>选择学习的语言</button>
</div>)
}
export default ButtonActive
Header.js代码如下:
import React from 'react'
const Header = (props) => {
return (<header>
<div>{props.obj.title}</div>
<div>{props.obj.des}</div>
<div>{props.obj.tips}</div>
</header>
)
}
Header.defaultProps = {
obj: {
title: '今天学习了吗?',
des: '大家好,我爱撸码。',
tips: '如果学不死就往死里学。'
}
}
export default Header
MySelectLanApp.js代码如下:
import React from 'react'
import Header from './Header'
import ButtonActive from './ButtonActive'
import AddLang from './AddLang'
import Options from './Options'
class MySelectLanApp extends React.Component {
constructor (props) {
super(props)
this.state = {
languages: props.languages
}
this.removeAllFunc = this.removeAllFunc.bind(this)
this.selectLanFunc = this.selectLanFunc.bind(this)
this.valueHandler = this.valueHandler.bind(this)
this.removeCurrentValue = this.removeCurrentValue.bind(this)
}
removeAllFunc () {
this.setState(() => ({languages: []}))
}
selectLanFunc () {
let len = this.state.languages.length;
let randomNum = Math.floor(Math.random() * len);
alert(`今天学习的语言是: ${this.state.languages[randomNum]}`);
}
valueHandler (value) {
if (this.state.languages.includes(value)) {
alert('不能重复提交')
}
else {
this.setState((preValue) => ({ languages: preValue.languages.concat(value)}))
}
}
removeCurrentValue (value) {
this.setState((preValue) => ({
languages: preValue.languages.filter((item) => {
return item !== value
})
}))
}
componentDidMount () {
this.setState(() => ({
languages: JSON.parse(localStorage.getItem('languages')) || []
}))
}
componentDidUpdate(preProps, preState) {
if (this.state.languages.length !== preState.languages.length) {
localStorage.setItem('languages', JSON.stringify(this.state.languages))
}
}
render () {
return (<div>
<Header/>
<main>
<ButtonActive isDisabled={this.state.languages.length == 0} removeAllFunc={this.removeAllFunc} selectLanFunc={this.selectLanFunc}></ButtonActive>
<AddLang valueHandler={this.valueHandler}></AddLang>
<Options languages={this.state.languages} removeCurrentValue={this.removeCurrentValue}></Options>
</main>
</div>)
}
}
MySelectLanApp.defaultProps = {
languages: []
}
export default MySelectLanApp
Option.js代码如下:
import React from 'react'
const Option = (props) => {
return (
props.languages.map((item, index) => {
return (<div key={`option${index}`}>
<li>{item}</li>
<button onClick={() => {
props.removeCurrentValue(item)
}}>删除</button>
</div>)
})
)
}
export default Option
Options.js代码如下:
import React from 'react'
import Option from './Option'
const Options = (props) => {
return (<ul>
<Option languages={props.languages} removeCurrentValue={props.removeCurrentValue}/>
</ul>)
}
export default Options
好的,我们利用react脚手架工具,用模块组件化开发的思想重新把我们的项目给重构了,我们再来看看,项目是否还能顺利跑起来:
好的一切正常,只不过我们经历了 jsx > 组件化 > 模块组件化。