React基础项目搭建

10 篇文章 0 订阅

基本内容构建

这里仅是配了一些个人项目常用的包和规范了下目录结构,具体项目需要根据个人适当修改

Demo命名的文件仅用于举例,可随意删改

搭建好的模板

git clone https://github.com/magezee/reactDemo.git
然后进入项目 npm install 下载依赖所需配置npm包
  • 使用脚手架构建项目
npx create-react-app project_name
  • 删除src目录下的所有文件,如有必要public目录下的图标文件也可删除

  • 在src目录下建立自己的index.js,启动项目的main是index.js

文件管理(默认统一规定)

  • 启动脚本管理

    常规的react项目都会有一个index.js和App.js

    index.js用于启动文件,通常只渲染app.js里导出的App组件和根页面

import React from 'react'
import {render} from 'react-dom'
import App from './App.js'

render(
    <App />,
    document.querySelector('#root')
)

App.js用于当做组件的根组件,导入并渲染所需子组件(不只是用作渲染,也用于进行数据处理和事件声明)

mport React,{Component} from 'react'
import { ComponentDemo } from './components'

export default class App extends Component {
    render() {
        return(
            <ComponentDemo/>
        )
    }
}
  • 组件目录管理

    src目录下新建一个目录components用于存储组件,每编写一个新组建,相应的再该目录下再新建一个组件名的目录,将组件文件放置于此

// /src/components/ComponentDemo
import React, { Component } from './react'

export default class ComponentDemo extends Component {
    render() {
        return (
            <div>
                A component for export
            </div>
        )
    }
}

​ 在components目录下新建一个index.js文件,目的是用于接收所有导入组件并导出,这样在使用组件时实际上只需要定位components即可

// /src/components/index.js
export {default as  ComponentDemo} from './ComponentDemo'
  • 页面

    /src目录下创建views目录

    然后建立各自的网页(使用components里的组件来组成页面),views下面的目录结构和components目录结构类似

  • 路由管理

    /src目录下创建routes目录和index.js,使用路由时则导入该index.js

  • 资源静态

    根目录下创建public目录一般资源均放于此(如图像、图标等)


webpack配置

做webpack配置:暴露项目的webpack.config.js文件,直接在该文件中进行修改配置(之前会有prod和dev两个环境的相关配置,但是新版run eject之后只存在一个webpack.config.js文件)

但是这样过于麻烦,因此通过react-app-rewired来配置webpack.config.js,这种配置方式无需生成更多额外的文件,同时更简单可控

yarn add react-app-rewired customize-cra

更改项目package.json文件

  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
	// 改为
  "scripts": {
    "start": "react-app-rewired start",
    "build": "react-app-rewired build",
    "test": "react-app-rewired test",
    "eject": "react-app-rewired eject"
  },

在项目根目录创建一个 config-overrides.js 用于修改默认配置

const { override, addLessLoader } = require('customize-cra');		// // 解构
module.exports = override(
	A(),
    B(),
    ...		// 各种配置项一起写在这里
)
less

使项目能识别less文件以代替css

yarn add less less-loader
const { override, addLessLoader } = require('customize-cra');
module.exports = override(
	addLessLoader({
		javascriptEnabled: true,
	}),
)
装饰器

使项目能使用装饰器

yarn add @babel/plugin-proposal-decorators	// 安装修饰符插件
const { override, addDecoratorsLegacy } = require('customize-cra')		
module.exports = override(
    addDecoratorsLegacy()   // 配置适配器模式方法 这里可以传很多方法
)

Redux配置

yarn add redux 
reducers

在项目src目录下创建reducers文件夹,用于统一存放reducer文件,创建index.js文件,用于统一导入reducer文件并导出

// /src/reducers/indes.js
import {combineReducers} from 'redux'	
import reducerDemo from './reducerDemo'
	
export default combineReducers({	// // redux专门用来提供合并reducers的工具
    reducerDemo,
})

一开始进行reducer的编写时,只需写明state和声明一个简单方法导出即可,后续再加功能

// /src/reducers/reducerDemo/indes.js
const reducerDemo= {
    demo:'this is a demo string'
}

export default (state = reducerDemo, action) => {
    switch(action.type) {
    	default:
    	return state
    }
}
store

在项目的src目录下创建store.js文件(注意只能存在一个store)

import {createStore} from 'redux'
import rootReducer from './reducers'

export default createStore(rootReducer)
actions

在项目src目录下创建actions文件夹,用于统一存放action文件

一般新建一个actionType.js文件统一对action的type进行管理并导出,然后另创建具体的action.js文件使用action创建函数的方式导出具体action

// /src/actions/actionType.js
export default {
    TYPE_DEMO_A: 'TYPE_DEMO_A',
    TYPE_DEMO_B: 'TYPE_DEMO_B' 
}
//  /src/actions/actionDemo.js
import actionType from './actionType'

export const typeA = () =>{
    return {
        type: actionType.TYPE_DEMO_A
    }
}

export const typeB = () =>{
    return {
        type: actionType.TYPE_DEMO_B
    }
}

在reducer里导入对应action

// /src/reducers/reducerDemo/index.js
import actionType from '../../actions/actionType'

const reducerDemo= {
    demo:'this is a demo string'
}

export default (state = reducerDemo, action) => {
    switch(action.type) {
		case actionType.TYPE_DEMO_A:
            return (( )=>{
                state.demo ='A was chosed'
                alert(state.demo)
                return state
            })() 
        case actionType.TYPE_DEMO_B:
            return (( )=>{
                state.demo ='B was chosed'
                alert(state.demo)
                return state
            })() 
        default:
            return state
    }
}

在要用的组件中dispatch

// /src/compoments/ComponentDemo/index.js
import React, { Component } from 'react'
import store from '../../store'
import {typeA, typeB} from '../../actions/actionDemo'
export default class ComponentDemo extends Component {
    render() {
        return (
            <div>
                <button onClick = {() => {
                    store.dispatch(typeA())
                }}>actionA</button>

                <button onClick = {() => {
                    store.dispatch(typeB())
                }}>actionB</button>
            </div>
        )
    }
}
Provider

使用provider进行快捷组件交流,不需要多层传递数据

使用时需要将其包在要传递组件的最外层,由于<App/>为组件渲染根元素,因此任意子组件内都可直接使用provider传递的数据,无需层层相传,必须要要拥有store属性,值为创建的store

// /index.js
import React from 'react'
import { render } from 'react-dom'
import App from './App'
import store from './store'
import {Provider} from 'react-redux'

console.log(store.getState())
render(
        
    <Provider store={store}>
        <App />
    </Provider>,   
    
    document.querySelector('#root')
)
connect

在对应组件内通过connect( )( )自动生成的容器组件(高阶组件),即可通过映射的方式使用redux的方法,而不是每次都要导入store

// /src/compoments/ComponentDemo/index.js
import React, { Component } from 'react'
import {typeA, typeB} from '../../actions/actionDemo'
import {connect} from 'react-redux'

class ComponentDemo extends Component {
    render() {
        console.log(this.props)
        return (
            <div>
                <button onClick = {() => {
                   this.props.chooseA()
                }}>actionA</button>

                <button onClick = {() => {
                    this.props.chooseB()
                }}>actionB</button>
            </div>
        )
    }
}

// 映射state到props
const mapStateToProps = (state) => {
    return {
        DomoProps: state
    }
}

// 映射dispatch到props
const mapDispatchToProps = (dispatch, ownProps) => {
    return {
      chooseA: () => { dispatch(typeA()) },
      chooseB: () => { dispatch(typeB()) }
    }
}

export default connect(mapStateToProps,mapDispatchToProps)(ComponentDemo) 
redux-thunk

使用redux-thunk处理异步action

yarn add redux-thunk

直接在store.js文件里导入即可(同时要导入使用applyMiddleware方法)

import {createStore, applyMiddleware} from 'redux'
import thunk from 'redux-thunk'
import rootReducer from './reducers'

export default createStore(
    rootReducer,
    applyMiddleware(thunk))

一般而言,会把同步action和异步操作分开,同步action用于定义action.type等数据,而异步只引用同步实现异步方法

//  /src/actions/actionDemo.js
import actionType from './actionType'

export const typeA = () =>{
    return {
        type: actionType.TYPE_DEMO_A
    }
}

export const typeB = () =>{
    return {
        type: actionType.TYPE_DEMO_B
    }
}


const typeC = () =>{
    return {
        type: actionType.TYPE_DEMO_C
    }
}

// 异步action 使用redux-thunk之后就可以在actionCreator里return一个方法,此方法的参数是dispatch(只要return了方法会自动识别并传入dispatch方法)
export const typeCAsynC = () => {
    return (dispatch) => {
        setTimeout(() =>{
            dispatch(typeC())		// 手动dispatch
        },2000)
    }
}

将其他文件实现按钮C的代码效果补上(并不重要可忽略)

// /src/actions/actionType.js
export default {
    TYPE_DEMO_A: 'TYPE_DEMO_A',
    TYPE_DEMO_B: 'TYPE_DEMO_B',
    TYPE_DEMO_C: 'TYPE_DEMO_C' 
}
// /src/reducers/reducerDemo/index.js
import actionType from '../../actions/actionType'

const reducerDemo= {
    demo:'this is a demo string'
}

export default (state = reducerDemo, action) => {
    switch(action.type) {
		case actionType.TYPE_DEMO_A:
            return (( )=>{
                state.demo ='A was chosed'
                alert(state.demo)
                return state
            })() 
        case actionType.TYPE_DEMO_B:
            return (( )=>{
                state.demo ='B was chosed'
                alert(state.demo)
                return state
            })() 
        case actionType.TYPE_DEMO_C:
            return (( )=>{
                state.demo ='C was chosed(delay)'
                alert(state.demo)
                return state
            })()     
        default:
            return state
    }
}
// /src/compoments/ComponentDemo/index.js
import React, { Component } from 'react'
import {typeA, typeB, typeCAsynC} from '../../actions/actionDemo'
import {connect} from 'react-redux'


class ComponentDemo extends Component {
    render() {
        console.log(this.props)
        return (
            <div>
                <button onClick = {() => {
                   this.props.chooseA()
                }}>actionA</button>

                <button onClick = {() => {
                    this.props.chooseB()
                }}>actionB</button>

                <button onClick = {() => {
                    this.props.chooseC()
                }}>actionC</button>
            </div>
        )
    }

    
}

// 映射state到props
const mapStateToProps = (state) => {
    return {
        DomoProps: state
    }
}

// 映射dispatch到props
const mapDispatchToProps = (dispatch, ownProps) => {
    return {
      chooseA: () => { dispatch(typeA()) },
      chooseB: () => { dispatch(typeB()) },
      chooseC: () => { dispatch(typeCAsynC()) }
    }
}



export default connect(mapStateToProps,mapDispatchToProps)(ComponentDemo) 

路由配置

yarn add react-router-dom

只需在项目文件index.js下使用一次Router包住渲染根组件

让路由工作,需要再导入Route组件,使用Router组件去调需要使用路由的组件,当访问指定路由时才渲染指定组件

// index.js
import React from 'react'
import { render } from 'react-dom'
import App from './App'
import store from './store'
import {Provider} from 'react-redux'
import {BrowserRouter as Router, Route} from 'react-router-dom'

console.log(store.getState())
render(
        
    <Provider store={store}>
        <Router>
            {/* component,path为固定属性不可更改,即路由为'/'时渲染App组件,和不写明path效果一样 */} 
            <Route component={App} path='/'/>  
        </Router>
    </Provider>,   
    
    document.querySelector('#root')
)

项目构建思想

层级关系:

  • index渲染根组件app和关键入口主路由(如首页和404等平级关系)

  • app渲染路由

  • 路由渲染页面

  • 页面渲染组件

组件区分(本博客这里没有体现):需要将组件分为UI组件和容器组件

  • UI组件只负责表现肉眼可见的视觉效果,数据仅通过props来获得,不参与数据逻辑交互
  • 容器组件负责UI组件的逻辑并将数据传递给UI组件
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
React是一个流行的JavaScript库,用于构建用户界面。在React项目中,搭建菜单和页面路由是非常常见的任务。 首先,我们需要选择一个合适的工具来创建React项目。常见的选择包括 create-react-app、Next.js或Gatsby等。这些工具可以帮助我们快速创建React项目基础结构。 在搭建菜单之前,我们需要安装并配置路由库。React Router是一个常用的路由库,可以帮助我们管理页面之间的导航。 首先,我们需要使用npm或yarn安装React Router库。安装完成后,我们可以在项目的根目录下创建一个Router组件,并引入所需的路由组件和相关配置。 接下来,我们可以在菜单组件中创建一个导航栏,包含各个页面的链接。这可以通过使用<Link>组件来实现。我们可以将这些链接连接到对应的页面组件,以便在用户点击时切换页面。 在每个页面组件中,我们可以根据需要展示不同的内容。可以使用React的组件和状态管理来构建页面的UI和逻辑。例如,我们可以使用React的useState钩子来管理页面的状态,并根据状态的变化来渲染不同的内容。 在路由配置中,我们可以指定路由和对应的页面组件之间的关联。可以使用<Route>组件来指定路由,以及关联的页面组件。这样,当用户访问特定的URL时,React Router会根据配置来加载对应的页面组件,并将其渲染到页面上。 总结起来,搭建React项目的菜单和页面路由需要安装和配置React Router库,并在菜单组件中创建导航栏链接。在每个页面组件中,我们可以使用React的组件和状态管理来构建页面的UI和逻辑。通过React Router的路由配置,我们可以指定路由和对应的页面组件之间的关联,从而实现页面的导航和切换。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值