react官方文档https://zh-hans.reactjs.org

使用脚手架快速搭建React项目

create-react-app是Facebook官方推出的脚手架,基本可以零配置搭建基于webpack的React开发环境

步骤:
打开控制台
进入你想要创建项目的目录文件下面
依次执行以下命令

npm install -g create-react-app /*安装全局的脚手架*/

create-react-app my-demo /*创建项目 my-demo是项目名字*/

cd my-demo /*进入目录 然后启动*/

npm start 

其他一些常用模块

npm install react-router-dom --save /*react路由*/

npm install react-loadable --save /*异步加载路由*/

npm install node-sass --save-dev /*sass文件样式*/

npm install axios --save /*数据请求*/

npm install redux react-redux --save-dev /*状态管理*/

npm install antd --save /*基于react的一个UI库,等同于vue的element ui*/

npm install svg-sprite-loader -D /*使用svg图标*/

修改webpack配置

方案一:通过craco插件修改配置

安装craco插件

npm install @craco/craco --save

修改package.json中运行命令

在项目根目录新建craco.config.js文件并进行配置

方案二:直接运行npm run eject反编译项目

使用'@'作为src文件

1.$npm run eject

2.在config/webpack.config.js文件的alias中插入代码'@': path.resolve('src')

路由配置

普通写法:直接在app.js里写路由配置

安装react-router-dom路由插件,react-router-dom 中文文档

npm install react-router-dom --save

在app.js里配置路由地址

// import { BrowserRouter, Route, NavLink, Link, Switch, Redirect } from 'react-router-dom'
import { HashRouter, Route, NavLink, Link, Switch, Redirect } from 'react-router-dom'
import Home from '@/views/home'
import Err404 from '@/views/err404'

function App() {
     return (
          <HashRouter>
               <main className="body-main">
                    <Switch>
                         <Redirect exact from="/" to="/home" />
                         <Route path="/home" component={Home} />
                         <Route path="/404" exact component={Err404} />
                         <Redirect to="/404" />
                    </Switch>
               </main>
               <footer className="body-footer">
                    <NavLink to="/find" activeClassName="footer-active">底部导航1</NavLink>
                    <NavLink to="/find1" activeClassName="footer-active">底部导航2</NavLink>
                    <NavLink to="/find2" activeClassName="footer-active">底部导航3</NavLink>
               </footer>
          </HashRouter>
     )
}
export default App;

BrowserRouter与HashRouter:BrowserRouter地址栏没有#,是需要服务端配合解析路由。 HashRouter地址栏有#,不需要服务端配合,是浏览器端解析路由。

Switch:它作用是一旦匹配到某个路径,就立即停止在向下匹配,并渲染该路径对应的组件,和js中switch...case的逻辑差不多

NavLink与Link:都是路径跳转组件,它们的区别在于NavLink可以实现路由链接的高亮,通过activeClassName指定样式名

Redirect:该组件就是,重定向路径(路径不匹配,或者只有访问的是某个路径时,才进行跳转,也就是 from 和 to 混用)。一般写在所有路由注册的最下方,当所有路由都无法匹配时,重定向到Redirect指定的路由

Route:该组件有几个属性。path为路由url地址。component指定路由对应的组件路径。exact属性表示精确匹配path

进阶写法:分离代码,实现路由模块化

我们在项目根目录创建router/index.js存放分离出来的路由配置,并对app.js进行改写。代码如下

// router/index.js文件
import Loadable from 'react-loadable'
import Loading from '@/components/loading'

const routes = [
	{
		path: '/home',
		component: Loadable({
			loader: () => import('@/views/home'),
			loading: Loading
		})
	},
	{
		path: '/user',
		component: Loadable({
			loader: () => import('@/views/user'),
			loading: Loading
		}),
		children: [
			{
				path: '/user/',
				component: Loadable({
					loader: () => import('@/views/user/list'),
					loading: Loading
				})
			},
			{
				path: '/user/userAdd',
				component: Loadable({
					loader: () => import('@/views/user/add'),
					loading: Loading
				})
			}
		]
	},
	{
		path: '/404',
		component: Loadable({
			loader: () => import('@/views/err404'),
			loading: Loading
		})
	},
]

export default routes



// app.js文件
import routers from './router' // 引入配置文件
// 改造Switch片段里的代码
<Switch>
     <Redirect exact from="/" to="/home" />
     {
          routers.map((item, key) => {
               return <Route key={key} path={item.path} exact={!!item.exact && (!item.children || !item.children.length)} render={props => (
                    <item.component {...props} routers={item.children} />
               )} />
          })
     }
     <Redirect to="/404" />
</Switch>



// user/index.js文件
function User(props) {
     return (
          <div>这是用户管理页面</div>
          <div>
               {
                    props.routers.map((item, key) => {
                         return <Route key={key} path={item.path} exact={!!item.exact && (!item.children || !item.children.length)} render={props => (
                              <item.component {...props} routers={item.children} />
                         )} />
                    })
               }
          </div>
     )
}
export default User 
PS:这里使用了react-loadable实现路由懒加载。在React16.6版本中,React团队已经包含了React.lazy()动态导入,我们还可以通过React.lazy()配合Suspense实现懒加载。大致使用如下,详细介绍请看文章
// router/index.js文件
import React from 'react'

const routes = [
     {
          path: '/home',
          component: React.lazy(() => import('@/views/home'))
     }
]
export default routes


// app.js文件
import routers from './router'
import { Suspense } from 'react'

<Switch>
     <Suspense fallback={<div>loading</div>}>
          {
               routers.map((item, key) => { ... })
          }
     </Suspense>
</Switch>

react中页面跳转

1.使用Link标签跳转

import { Link } from 'react-router-dom'
<Link to="/home">首页</Link>

2.js事件跳转

<span onClick={e => props.history.push('/home')}>首页</span>

3.返回上一页

<span onClick={e => props.history.goBack()}>返回</span>

React如何优雅的使用svg图标组件

参考文章:react项目中如何优雅的使用 svg

1.安装 svg-sprite-loader

npm i svg-sprite-loader -D

2.配置 /config/webpack.config.js

3.创建 /src/assets/icons/svg文件夹、/src/assets/icons/index.js文件

// src/assets/icons/index.js文件
const requireAll = requireContext => requireContext.keys().map(requireContext);
const svgs = require.context("./svg", false, /.svg$/);
requireAll(svgs);


// src/index.js文件
import "@/assets/icons";

4.创建 /src/components/SvgIcon组件,并在SvgIcon目录下添加index.js文件

// src/components/SvgIcon/index.js文件
import React from "react"
import PropTypes from "prop-types"

const svgClass = {
  display: 'inline-block',
  overflow: 'hidden',
  fontSize: '14px',
  minWidth: '14px',
  width: '1em',
  height: '1em'
}

const SvgIcon = props => {
  const { iconClass, fill, style } = props
  const currStyle = Object.assign({}, svgClass, style)

  return (
    <i aria-hidden="true" className="anticon">
      <svg style={currStyle}>
        <use xlinkHref={"#icon-" + iconClass} fill={fill} />
      </svg>
    </i>
  )
}

SvgIcon.propTypes = {
  iconClass: PropTypes.string.isRequired,
  fill: PropTypes.string
}

SvgIcon.defaultProps = {
  fill: "currentColor",
  style: {}
}

export default SvgIcon

5.使用组件

import SvgIcon from "@/components/SvgIcon";

const searchIcon = {
  fontSize: '20px'
}
const Demo = () => {
  return <SvgIcon style={searchIcon} iconClass="search" fill="#8a8a8a" />
};

export default Demo

React创建组件

类组件

import React from "react"

export class MyDemo extends React.Component {
    // 这里只列举几个常用的生命周期回调。更多回调请查看官网文档
    
    constructor(props) {
        // 类的构造函数,初始化state、方法绑定等
        super(props);
        this.state = {opacity: 1.0};
    }

    componentDidMount() {
        // 组件首次渲染完成。PS:从服务器获取数据之类的一般写在这个回调里
    }

    componentDidUpdate() {
        // 在组件完成更新后立即调用,首次渲染不会执行此方法。PS:如果你对更新前后的 props 进行了比较,也可以选择在此处进行网络请求。
    }

    componentWillUnmount() {
        // 销毁组件前调用
    }

    render() {
        // 渲染组件
        return (<div>组件的html代码</div>)
    }
}
export default MyDemo 

函数组件

函数组件中不存在state状态和生命周期回调,我们需要通过 React Hook 实现。详细介绍请查看文章React函数组件使用State和生命周期方法

import React, { useState, useEffect } from 'react';

function MyDemo(props) {
    const [data, setData] = useState({ opacity: 1.0 }); // 等价于类组件中的 this.state = {data: {opacity: 1.0}}。setData为赋值data的函数

    useEffect(() => {
        console.log('首次渲染')

        return () => {
            console.log('即将卸载')
        }
    }, [])

    return (<div>组件的html代码</div>)
}
export default MyDemo

使用redux状态管理

// 安装命令
npm install redux react-redux --save-dev


// 新建/store/index.js
import { createStore } from 'redux'

const defaultState = {
	r_scrollAuto: false, // 框架.body-main的-webkit-overflow-scrolling样式
}

export default createStore((state, action) => {
	switch (action.type) {
		case 'SCROLLAUTO':
			return Object.assign({}, state, {r_scrollAuto: action.auto})
		default:
			return state
	}
}, defaultState)


// 修改App.js
import { Provider } from 'react-redux'
import store from '@/store'

function App() {
	return (
		<provider store={store}>
			<hashrouter>
				// ...其他代码...
			</hashrouter>
		</provider>
	)
}


// 组件中使用(User组件为例)
import { useDispatch, useSelector } from 'react-redux'
function User(props) {
	const auto = useSelector(state => state.r_scrollAuto)
	const dispatch = useDispatch()

	return <button click={e => dispatch({type: 'SCROLLAUTO', auto: !auto})}>点击</button>
} 

使用mockjs模拟api请求

1.安装mockjs

npm i mockjs -D

2.src目录下新建mock/index.js

import Mock from 'mockjs'

// 首页banner
Mock.mock('/api/getBannerList', 'get', {
    success: true,
    message: '',
    data: [
        'https://bpic.588ku.com/element_banner/20/21/08/c413e5f6d74e67fe079a2116be950ebe.png!/unsharp/true/compress/true',
        'https://bpic.588ku.com/element_banner/20/21/08/369b331152285e2b37f74acef79ea413.png!/unsharp/true/compress/true'
    ]
})

// 热卖推荐
Mock.mock('/api/hotRecommend', 'get', {
    success: true,
    message: '',
    data: [
        {
            id: 1,
            name: '商品1',
            img: 'https://bpic.588ku.com/element_banner/20/21/08/c413e5f6d74e67fe079a2116be950ebe.png!/unsharp/true/compress/true'
        }
    ]
})

export default Mock

3.引入并请求数据

import '@/mock'
import axios from 'axios'

axios.get('/api/getBannerList').then(result => {
    console.log(result)
}, err => {
    console.log(err)
})

自己常用的项目结构

├── config          --------------------webpack配置
├── public          --------------------出口
│   ├── favicon.ico
│   ├── index.html
│   └── manifest.json
├── src           ----------------------源码目录
│   ├── api       ----------------------API目录
│   │   ├── api.js
│   │   └── server.js
│   ├── assets   -----------------------资源目录
│   │   ├── style
│   │   ├── image
│   │   └── icons
│   ├── components   -------------------公共组件
│   ├── index.js    --------------------入口
│   ├── views       --------------------页面目录
│   ├── router   -----------------------路由
│   │   └── index.js
│   ├── store   ------------------------react-redux状态管理目录
│   │   ├── store.js
│   │   └── user
│   └── utils  ------------------------公用方法
│       ├── request.js  ---------------异步加载组件
│       └── commons.js  ---------------公用方法
├── package-lock.json
├── package.json    --------------------项目package.json
└── README.md      ----------------------README