2-4、React脚手架的使用,以及组件模块构建。

本节将开启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脚手架的使用:

好的,在之前的项目,我们都是通过引入reactcdn并且开了live-server服务以及babeljsx语法以及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脚手架工具的方式,所以会在全局有ReactReactDOM,只不过我们现在是在脚手架工具里,就可以使用es6的模块导入语法,在index.js文件上最开头加上如下代码:

import React from 'react'
import ReactDOM from 'react-dom'

一保存,看到又报错:
在这里插入图片描述
我们打开public文件夹下的index.html

在这里插入图片描述
发现它这边的idroot,那么我们把这个id改成app,因为我们以前采用cdn的方式,就是去渲染idappdom节点。好的一保存,发现页面还是我们熟悉的,我们去跑一下如下:
在这里插入图片描述
好的看见项目还是一如既往的跑起来了,只不过这次是采用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 > 组件化 > 模块组件化。


版权声明:本文为weixin_44103733原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。