React 项目中常用第三方库

3,121 阅读6分钟

styled-components

文档

styled-components.com/

安装

npm install --save styled-components

createGlobalStyle 设置全局样式

styled-components v4.0 之后定义全局样式的方法跟之前不一样

// 全局样式 style.js
import { createGlobalStyle } from 'styled-components'
const GlobalStyle = createGlobalStyle`
  body {
    margin: 0;
    padding: 0;
    font-family: sans-serif;
    background: #eee;
  }
`
export default GlobalStyle

// 在项目入口文件中引入全局样式
import React from 'react'
import ReactDOM from 'react-dom'
import GlobalStyle from './style.js'
import App from './App'
const Wrapper  = (
  <React.Fragment>
    <GlobalStyle />
    <App />
  </React.Fragment>
)
ReactDOM.render(Wrapper, document.getElementById('root'))

styled 设置组件样式

style.js

import styled from 'styled-components'
// 设置样式
export const HeaderWrapper = styled.div`
  height: 56px;
  background: #fff;
  border-bottom: 1px solid #f0f0f0;
`
// 设置标签属性
export const HeaderLogo = styled.a.attrs({
  href: '/'
})`
  color: #0ea86a;
  display: flex;
  align-items: center;
  height: 100%;
  font-size: 24px;
`

业务组件

import React from 'react'
import { HeaderWrapper } from './style'
class Header extends React.Component {
  render () {
    return (
      <HeaderWrapper>这是一个header</HeaderWrapper>
    )
  }
}
export default Header

从业务组件接收参数

// style.js
import styled from 'styled-components'
exports const Item = styled.div`
    background: url(${(props) => props.imgUrl})
`

// index.js
import React from 'react'
import { Item } from './style'
class Home extends React.Component {
    render () {
        return (
            <Item imgUrl="https://cdn.baidu.com"></Item>
        )
    }
}

Ant-Design

文档

ant.design/

安装

npm install antd --save

设置全局样式

文档 ant.design/docs/react/…

安装必要的Package

npm install react-app-rewired customize-cra -D
npm install less less-loader babel-plugin-import -D

在根目录下创建config-overrides.js

const { override, fixBabelImports, addLessLoader } = require('customize-cra')
module.exports = override(
  fixBabelImports('import', {
    libraryName: 'antd',
    libraryDirectory: 'es',
    style: true,
  }),
  addLessLoader({
    javascriptEnabled: true,
    // 样式配置写在这里
    modifyVars: {
      '@primary-color': '#1DA57A'
    }
  })
)

页面上使用

// src/App.js
import React, { Component } from 'react';
import { Button } from 'antd';
import './App.css';
class App extends Component {
    render() {
      return (
        <div className="App">
          <Button type="primary">Button</Button>
        </div>
      );
    }
}
export default App;

react-transition-group

文档

github.com/reactjs/rea…

安装

npm install react-transition-group --save

react-redux

安装

npm install react-redux --save

Provider 组件

通过 Provider 将 Redux 的 store 提供给 Provider 下的所有组件。

import { Provider } from 'react-redux';
import store from './store';
import ReactRedux from './ReactRedux';
// 通过 Provider 将 Redux 的 store 提供给 Provider 下的所有组件
const App = (
  <Provider store={store}>
    <ReactRedux />,
  </Provider>
)
ReactDOM.render(App, document.getElementById('root'));

connect()

使业务组件和store进行连接,该业务组件必须在Provider组件下

import React, { Component, Fragment } from 'react'
import { connect } from 'react-redux'
class ReactRedux extends Component {
  constructor (props) {
    super(props)
  }
  render () {
    return (
      <Fragment>
        <div>
          <input placeholder="你接下来想做什么" value={this.props.inputValue} onChange={this.props.changeInputValue}/>
          <button onClick={this.props.handleClick}>提交</button>
        </div>
        <ul>
          {this.props.list.map((item, index) => (<li key={index} onClick={() => {
            return this.props.handleItemDelete(index)
          }}>{item}</li>))}
        </ul>
      </Fragment>
    )
  }
}
// 将 Redux 的 store 挂载到 props
const mapStateToProps = (state) => {
  return {
    inputValue: state.inputValue,
    list: state.list
  }
}
// 将 Redux 的 dispatch 挂载到 props
const mapDispatchToProps = (dispatch) => {
  return {
    changeInputValue (e) {
      const action = {
        type: 'change_input_value',
        value: e.target.value
      }
      dispatch(action)
    },
    handleClick () {
      const action = {
        type: 'add_list_item'
      }
      dispatch(action)
    },
    handleItemDelete (itemIndex) {
      const action = {
        type: 'delete_list_item',
        itemIndex
      }
      dispatch(action)
    }
  }
}
export default connect(mapStateToProps, mapDispatchToProps)(ReactRedux);

redux-devtools-extension

Redux 浏览器调试插件

文档

github.com/zalmoxisus/…

immutable-js && redux-immutable

文档

github.com/immutable-j…

安装

npm install immutable --save

fromJS()

js对象,转化为immutable对象

import { fromJS } from 'immutable'
const defaultState = fromJS({
  focused: false
})
// immutable 对象获取属性
defaultState.get('focused')

immutableObj.get()

immutable对象获取属性

immutableObj.get('focused')

immutableObj.set()

immutableObj.set()会结合之前immutableObj的值和设置的值,返回一个全新的对象。不会直接修改旧的数据,而是通过返回新对象的方式来修改数据

immutableObj.set('focused', true) // immutable 对象设置值

[重要]通过请求获取 immutable 数据

在通过ajax获取数据,并将数据设置到 immutable 对象时,需要注意,通过ajax获取到的为普通js对象,例如: 数组。但是当 immutable 对象初始化空数组时,已经将普通 js 数组转化为 immutable 的数组,所以在设置值时需要通过fromJS()将获取到的数据转化为immutable的数据类型,再赋值。

export const setSearchInfo = (data) => ({
  type: actionTypes.SET_SEARCH_INFO,
  data: fromJS(data)
})

redux-immutable

将 redux 和 immutable 结合

安装

npm install redux-immutable --save

store 中配置

- import { combineReducers } from 'redux' // 直接使用 redux
+ import { combineReducers } from 'redux-immutable' // 直接使用 immutable
import { reducer as headerReducer } from '../common/header/store'

// 使用 redux-immutable 之后,store.state 将变为一个 immutable 对象
const reducer = combineReducers({
  header: headerReducer
})
export default reducer

页面上使用

state.get('header').get('focused') // immutable 对象获取属性
// or
state.getIn(['header', 'focused']) // 多级 immutable 对象获取属性

redux-thunk

文档

github.com/reduxjs/red…

安装

npm install redux-thunk --save

在Store中的配置

import { createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
import reducer from './reducer';
// https://github.com/zalmoxisus/redux-devtools-extension
const middlewareList = [thunk]
const composeEnhancers = typeof window === 'object' && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({}) : compose;
const enhancer = composeEnhancers(applyMiddleware(...middlewareList));
const store = createStore(reducer, enhancer);
// 不需要使用 devtools 时的配置,devtools也是一个中间件
// const store = createStore(
//   reducer,
//   applyMiddleware(thunk),
// );
export default store;

在不使用redux-thunk的时候,action返回的是一个对象,在使用redux-thunk之后,action可以返回一个函数
actionCreator.js中配置

import { INIT_STORE_DATA } from './actionTypes';
export const getInitStoreData = (data) => ({
  type: INIT_STORE_DATA,
  data
});
// 当使用 redux-thunk 返回一个函数时,函数可以接收到 store 的 dispatch 方法作为参数
export const getTodoList = () => {
    return (dispatch) => {
        axios.get('/api/todolist').then((res) => {
            const data = res.data;
            const action = getInitStoreData(data);
            dispatch(action);
        });
    }
}

在组件中使用

import { getTodoList } from './store/actionCreator';
componentDidMount () {
    const action = getTodoList();
    store.dispatch(action);
}

Axios

文档

www.kancloud.cn/yunye/axios…

安装

npm install axios --save

React-router-dom

安装

npm install react-router-dom --save

简单使用

import { BrowserRouter, Route } from 'react-router-dom'
// exact 表示必须路径完全相同才会展示
const App = () => {
  return (
  <React.Fragment>
    <BrowserRouter>
      <Route path='/' exact render={() => (<div>Home Page</div>)}></Route>
      // 访问路径: /detail/123456
      <Route path='/detail/:id' exact component={Detail}></Route>
    </BrowserRouter>
  </React.Fragment>
  )
}
export default App

单页应用跳转及参数获取

第一种

路由设置

import { BrowserRouter, Route } from 'react-router-dom'

<BrowserRouter>
    // 访问路径: /detail/123456
    <Route path='/detail/:id' exact component={Detail}></Route>
</BrowserRouter>

跳转设置

import { Link } from 'react-router-dom'
render () {
    return (
        <div>
            // 动态路由
            <Link to={'/detail/' + this.state.id}>
                <div>跳转到详情</div>
            </Link>
        </div>
    )
}

目标路由获取参数

this.props.match.params.id

第二种

路由设置

import { BrowserRouter, Route } from 'react-router-dom'

<BrowserRouter>
    // 访问路径: /detail?id=123456
    <Route path='/detail' exact component={Detail}></Route>
</BrowserRouter>

跳转设置

import { Link } from 'react-router-dom'
render () {
    return (
        <div>
            // 动态路由,第一种写法
            <Link to={'/detail?id=' + this.state.id}>
                <div>跳转到详情</div>
            </Link>
        </div>
    )
}

目标路由获取参数

this.props.location.search

react-infinite-scroller

滚动自动加载列表

文档

github.com/CassetteRoc…

安装

npm install react-infinite-scroller --save

react-virtualized

结合react-virtualized实现滚动加载无限长列表,带有虚拟化(virtualization)功能,能够提高数据量大时候长列表的性能。

virtualized是在大数据列表中应用的一种技术,主要是为了减少不可见区域不必要的渲染从而提高性能,特别是数据量在成千上万条效果尤为明显

文档

github.com/bvaughn/rea…

安装

npm install react-virtualized --save

React-loadable

用于动态加载组件

文档

github.com/jamiebuilds…

安装

npm install react-loadable --save

简单使用

在页面组件目录下创建loadable.js

// 使用 react-loadable
import React from 'react'
import Loadable from 'react-loadable'
import Loading from './my-loading-component';

const LoadableComponent = Loadable({
  loader: () => import('./index'), // 需要异步加载的组件
  loading () {
    return <div>正在加载...</div>
  }
})
export default <LoadableComponent />

在路由文件中使用,从之前引入 组件的index.js 改为引入 **组件的loadable.js

import React from 'react'
import { Provider } from 'react-redux'
import { BrowserRouter, Route } from 'react-router-dom'

import store from './store'
import Home from './pages/home'
import Detail from './pages/detail/loadable'

// 通过 Provider 将 Redux 的 store 提供给 Provider 下的所有组件
const App = () => {
  return (
    <Provider store={store}>
      <BrowserRouter>
        <Route path='/' exact component={Home}></Route>
        <Route path='/detail/:id' exact component={Detail}></Route>
        <Bottom />
      </BrowserRouter>
    </Provider>
  )
}
export default App

在页面中,如果 需要使用路由传递的参数 ,需要使用withRouter()

import React from 'react'
import { withRouter } from 'react-router-dom'
class Detail extends React.Component {
    constructor (props) {
        super(props)
    }
    render () {
        return (
            <div>{this.props.match.params.id}</div>
        )
    }
}
export default withRouter(Detail)

Lodash

文档

www.lodashjs.com/

对象/数组 深度比较

_.isEqual(nextProps.list, this.props.list) // 判断是否相等