Skip to content

React 常用插件 ​

ESLint 配置 ​

React 项目 ESLint ​

json
{
  "env": { "browser": true, "node": true, "es6": true },
  "parser": "babel-eslint",
  "extends": ["react-app", "eslint:recommended", "plugin:react/recommended"],
  "rules": {
    "comma-dangle": [2, "never"],
    "no-console": 0,
    "react/jsx-key": 2,
    "react/jsx-no-duplicate-props": 2,
    "react/no-array-index-key": 2,
    "react/no-direct-mutation-state": 2,
    "react/self-closing-comp": 2
  }
}
{
  "env": { "browser": true, "node": true, "es6": true },
  "parser": "babel-eslint",
  "extends": ["react-app", "eslint:recommended", "plugin:react/recommended"],
  "rules": {
    "comma-dangle": [2, "never"],
    "no-console": 0,
    "react/jsx-key": 2,
    "react/jsx-no-duplicate-props": 2,
    "react/no-array-index-key": 2,
    "react/no-direct-mutation-state": 2,
    "react/self-closing-comp": 2
  }
}

Parsing error: Unexpected token = ​

使用 babel-eslint 解析:

js
module.exports = {
  parser: 'babel-eslint'
}
module.exports = {
  parser: 'babel-eslint'
}

styled-components ​

通过组件形式写样式:

tsx
import styled from 'styled-components'

const Button = styled.button`
  display: inline-block;
  background: ${props => props.primary ? 'palevioletred' : 'white'};
  color: ${props => props.primary ? 'white' : 'palevioletred'};

  &:focus { background: #000; }
`
import styled from 'styled-components'

const Button = styled.button`
  display: inline-block;
  background: ${props => props.primary ? 'palevioletred' : 'white'};
  color: ${props => props.primary ? 'white' : 'palevioletred'};

  &:focus { background: #000; }
`

主题 ​

tsx
import { ThemeProvider } from 'styled-components'

<ThemeProvider theme={{ main: 'mediumseagreen' }}>
  <Button>Themed</Button>
</ThemeProvider>

// 函数组件获取主题
import { useTheme } from 'styled-components'
const theme = useTheme()
import { ThemeProvider } from 'styled-components'

<ThemeProvider theme={{ main: 'mediumseagreen' }}>
  <Button>Themed</Button>
</ThemeProvider>

// 函数组件获取主题
import { useTheme } from 'styled-components'
const theme = useTheme()

Emotion(CSS-in-JS) ​

bash
yarn add @emotion/core
yarn add @emotion/core
jsx
/** @jsx jsx */
import { css, jsx } from '@emotion/core'

<div css={css`
  padding: 32px;
  color: black;
  &:hover { color: white; }
`} />
/** @jsx jsx */
import { css, jsx } from '@emotion/core'

<div css={css`
  padding: 32px;
  color: black;
  &:hover { color: white; }
`} />

Mock 数据 ​

mockjs ​

bash
npm i mockjs
npm i mockjs
js
import Mock from 'mockjs'
Mock.mock('/list', 'get', {
  'object|2-4': { 110000: '北京市', 120000: '天津市' }
})
import Mock from 'mockjs'
Mock.mock('/list', 'get', {
  'object|2-4': { 110000: '北京市', 120000: '天津市' }
})

msw + faker.js ​

bash
npx msw init public/
npm i @mswjs/data @faker-js/faker
npx msw init public/
npm i @mswjs/data @faker-js/faker
js
import { setupWorker } from 'msw'
import { rest } from 'msw'

export const worker = setupWorker(
  rest.get('/login', (req, res, ctx) => {
    return res(ctx.json({ username: 'wing' }))
  })
)

// 入口文件
if (process.env.NODE_ENV === 'development') {
  const { worker } = require('./mocks/browser')
  worker.start()
}
import { setupWorker } from 'msw'
import { rest } from 'msw'

export const worker = setupWorker(
  rest.get('/login', (req, res, ctx) => {
    return res(ctx.json({ username: 'wing' }))
  })
)

// 入口文件
if (process.env.NODE_ENV === 'development') {
  const { worker } = require('./mocks/browser')
  worker.start()
}

动画 ​

bash
npm i react-transition-group
npm i react-transition-group
jsx
import { CSSTransition, TransitionGroup } from 'react-transition-group'

<CSSTransition in={flag} timeout={2000} classNames="fade" unmountOnExit>
  <div>动画内容</div>
</CSSTransition>
import { CSSTransition, TransitionGroup } from 'react-transition-group'

<CSSTransition in={flag} timeout={2000} classNames="fade" unmountOnExit>
  <div>动画内容</div>
</CSSTransition>

react-query(数据请求) ​

tsx
import { useQuery, useMutation, useQueryClient } from 'react-query'

// GET 请求
const { data, isLoading, refetch } = useQuery(
  ['todos', page],
  () => fetch('/api/todos').then(res => res.json()),
  { enabled: true, retry: 3 }
)

// 其他请求
const mutation = useMutation(postTodo, {
  onSuccess: () => queryClient.invalidateQueries('todos')
})
mutation.mutate({ title: '1234' })
import { useQuery, useMutation, useQueryClient } from 'react-query'

// GET 请求
const { data, isLoading, refetch } = useQuery(
  ['todos', page],
  () => fetch('/api/todos').then(res => res.json()),
  { enabled: true, retry: 3 }
)

// 其他请求
const mutation = useMutation(postTodo, {
  onSuccess: () => queryClient.invalidateQueries('todos')
})
mutation.mutate({ title: '1234' })

Echarts ​

  • echarts-for-react — React 中简单使用 Echarts
  • echarts-wordcloud — 词云图

二维码 ​

bash
npm install qrcode.react
npm install qrcode.react
jsx
import { QRCodeSVG } from 'qrcode.react'
<QRCodeSVG value="https://reactjs.org/" />
import { QRCodeSVG } from 'qrcode.react'
<QRCodeSVG value="https://reactjs.org/" />

其他插件 ​

插件说明
react-lazyload图片/组件懒加载
react-scroll滚动控制
react-router-cache-route路由缓存
classnames动态 class
react-fontawesomeSVG 图标库
react-cropper图片裁剪
react-split-pane面板拖拽
memoize-one记忆函数(相同参数返回上次结果)
mitteventBus 事件监听
formik + yup表单校验
@ebay/nice-modal-reactModal 管理

Mobx ​

安装 ​

bash
npm i mobx mobx-react
npm i mobx mobx-react

Store ​

js
import { observable, action, configure, runInAction } from 'mobx'

configure({ enforceActions: 'always' })

class Store {
  @observable number = 0

  @action add = () => { this.number++ }

  @action load = async () => {
    const data = await getData()
    runInAction(() => { this.name = data.name })
  }
}

export default new Store()
import { observable, action, configure, runInAction } from 'mobx'

configure({ enforceActions: 'always' })

class Store {
  @observable number = 0

  @action add = () => { this.number++ }

  @action load = async () => {
    const data = await getData()
    runInAction(() => { this.name = data.name })
  }
}

export default new Store()

组件中使用 ​

jsx
import { observer, inject } from 'mobx-react'

@inject('store')
@observer
class Child extends Component {
  render() {
    return <div>{this.props.store.number}</div>
  }
}
import { observer, inject } from 'mobx-react'

@inject('store')
@observer
class Child extends Component {
  render() {
    return <div>{this.props.store.number}</div>
  }
}

支持装饰器 ​

js
// .babelrc
{
  "plugins": [["@babel/plugin-proposal-decorators", { "legacy": true }]]
}
// .babelrc
{
  "plugins": [["@babel/plugin-proposal-decorators", { "legacy": true }]]
}

Redux-Saga ​

jsx
import { takeEvery, put } from 'redux-saga/effects'

function* mySagas() {
  yield takeEvery('GET_LIST', getList)
}

function* getList() {
  const res = yield new Promise(resolve => {
    setTimeout(() => resolve(['111', '222']), 2000)
  })
  yield put({ type: 'CHANGE_LIST', payload: res })
}
import { takeEvery, put } from 'redux-saga/effects'

function* mySagas() {
  yield takeEvery('GET_LIST', getList)
}

function* getList() {
  const res = yield new Promise(resolve => {
    setTimeout(() => resolve(['111', '222']), 2000)
  })
  yield put({ type: 'CHANGE_LIST', payload: res })
}