React 技术栈

React,React-Dom,Redux,React-Redux,React-Router基本依赖就不多说了

  • React-Router-Redux
    使用Redux来管理应用程序状态,使用React Router进行路由管理。但是两个库不协调,当你重播actions时React Router不会在页面之间导航。它控制应用的state的一个很重要的部分:URL。这个库帮助你保持这个状态与你的Redux存储同步。
    注意:使用redux和react router时,这个库不是必须的。你可以不用任何其它的库只使用它们两个。如果你关心记录,持续,重播,用户行为和时光机,则它是有用的。如果你不在乎这些功能,那就直接使用Redux 和react router吧。
// 三步走
import React from 'react'  
import ReactDOM from 'react-dom'  
import { createStore, combineReducers } from 'redux'  
import { Provider } from 'react-redux'  
import { Router, Route, browserHistory } from 'react-router'  
// 第一步:引入react-router-redux
import { syncHistoryWithStore, routerReducer } from 'react-router-redux'
import reducers from '/reducers'

// 第二步:添加自身的reducer到redux的createStore中(以routing为key)
const store = createStore(  
  combineReducers({
    ...reducers,
    routing: routerReducer
  })
)

// 第三步、创建一个增强版的history对象(能让store和导航事件保持同步)
const history = syncHistoryWithStore(browserHistory, store)

ReactDOM.render(  
  
    
      
        
        
      
    
  ,
  document.getElementById('mount')
)
  • Redux-Actions
    提供更为便捷的reducer创建方法,主要提供了API:handleActions
// 普通方式创建reducer
const defaultState = 10
const reducer = (state = defaultState, action) => {
  switch (action.type) {
    case Constants.INCREASE:
      return state + 1
    case Constants.DECREASE:
      return state - 1
    default:
      return state
  }
}
export default reducer

// 使用handleActions创建reducer
// 语法:handleActions({actionCreator},initialState)

import { handleActions } from 'redux-actions'
import { LOGIN_SUCCEEDED, LOGIN_FAILED, LOGOUT_SUCCEEDED, LOGOUT_FAILED} from '../constants/login'

export default handleActions(
    {
        [LOGIN_SUCCEEDED](state, action) {
            return { ...state, hasLogin: true }
        },
        [LOGIN_FAILED](state, action) {
            alert(action.message)
            return state
        },
        [LOGOUT_SUCCEEDED](state, action) {
            return { ...state, hasLogin: false }
        },
        [LOGOUT_FAILED](state, action) {
            alert(action.message)
            return state
        },
    },
    {
        hasLogin: false,
    },
)
  • Reselect
    Reselect 库可以创建可记忆的(Memoized)、可组合的 selector 函数。Reselect selectors 可以用来高效地计算 Redux store 里的衍生数据。主要用在mapStateToProps中。
// 不使用reselect的通常写法:
import { connect } from 'react-redux'
import { toggleTodo } from '../actions'
import TodoList from '../components/TodoList'

const getVisibleTodos = (todos, filter) => {
  switch (filter) {
    case 'SHOW_ALL':
      return todos
    case 'SHOW_COMPLETED':
      return todos.filter(t => t.completed)
    case 'SHOW_ACTIVE':
      return todos.filter(t => !t.completed)
  }
}

const mapStateToProps = (state) => {
  return {
    todos: getVisibleTodos(state.todos, state.visibilityFilter)
  }
}

const mapDispatchToProps = (dispatch) => {
  return {
    onTodoClick: (id) => {
      dispatch(toggleTodo(id))
    }
  }
}

const VisibleTodoList = connect(
  mapStateToProps,
  mapDispatchToProps
)(TodoList)

export default VisibleTodoList

上面的示例中,mapStateToProps 调用了 getVisibleTodos 来计算 todos。运行没问题,但有一个缺点:每当组件更新时都会重新计算 todos。如果 state tree 非常大,或者计算量非常大,每次更新都重新计算可能会带来性能问题。Reselect 能帮你省去这些没必要的重新计算

// 使用reselect版本,三步走:

// 第一步:引入createSelector函数
import { createSelector } from 'reselect'

// 第二步:创建普通无记忆selector(即不涉及计算操作,仅是取值操作)
const getVisibilityFilter = (state) => state.visibilityFilter
const getTodos = (state) => state.todos

// 第三步:创建可记忆selector
export const getVisibleTodos = createSelector(
  [ getVisibilityFilter, getTodos ],
  (visibilityFilter, todos) => {
    switch (visibilityFilter) {
      case 'SHOW_ALL':
        return todos
      case 'SHOW_COMPLETED':
        return todos.filter(t => t.completed)
      case 'SHOW_ACTIVE':
        return todos.filter(t => !t.completed)
    }
  }
)

如果你在使用 React Redux,你可以在 mapStateToProps() 中当正常函数来调用 selectors

import { connect } from 'react-redux'
import { toggleTodo } from '../actions'
import TodoList from '../components/TodoList'
import { getVisibleTodos } from '../selectors'

const mapStateToProps = (state) => {
  return {
    todos: getVisibleTodos(state)
  }
}

const mapDispatchToProps = (dispatch) => {
  return {
    onTodoClick: (id) => {
      dispatch(toggleTodo(id))
    }
  }
}

const VisibleTodoList = connect(
  mapStateToProps,
  mapDispatchToProps
)(TodoList)

export default VisibleTodoList

更多操作,请参看文档

  • Redux-Saga
    1、redux-saga 是一个用于管理 Redux 应用异步操作的中间件(又称异步 action)。 redux-saga 通过创建 Sagas 将所有的异步操作逻辑收集在一个地方集中处理,可以用来代替 redux-thunk 中间件。
    2、Sagas 监听发起的action,然后决定基于这个 action来做什么:是发起一个异步调用(比如一个 fetch 请求),还是发起其他的action到Store,甚至是调用其他的 Sagas
// sagas.js基本套路:(put,call等effect定义异步操作,takeEvery或者takeLatest调用异步操作,一般一个action对应三个type,put,call等占用成功和失败,takeEvery占用请求开始)
import { put, call, take,fork } from 'redux-saga/effects';
import { takeEvery, takeLatest } from 'redux-saga'

export const delay = ms => new Promise(resolve => setTimeout(resolve, ms));

function* incrementAsync() {
  // 延迟 1s 再执行 + 1操作
  yield call(delay, 1000);
  yield put({ type: 'INCREMENT' });
}

export default function* rootSaga() {
  // while(true){
  //   yield take('INCREMENT_ASYNC');
  //   yield fork(incrementAsync);
  // }

  // 下面的写法与上面的写法上等效
  yield* takeEvery("INCREMENT_ASYNC", incrementAsync)
}

整合redux的用法:

import React from 'react';
import ReactDOM from 'react-dom';
import {createStore, applyMiddleware} from 'redux'
import createSagaMiddleware from 'redux-saga'

import rootSaga from './sagas'
import Counter from './Counter'
import rootReducer from './reducers'

const sagaMiddleware = createSagaMiddleware()
let middlewares = []
middlewares.push(sagaMiddleware)

const createStoreWithMiddleware = applyMiddleware(...middlewares)(createStore)
const store = createStoreWithMiddleware(rootReducer)

sagaMiddleware.run(rootSaga)

const action = type => store.dispatch({ type })

function render() {
  ReactDOM.render(
     action('INCREMENT')}
      onDecrement={() => action('DECREMENT')}
      onIncrementAsync={() => action('INCREMENT_ASYNC')} />,
    document.getElementById('root')
  )
}

render()

store.subscribe(render)

更多用法参考文档

  • classnames
    A simple javascript utility for conditionally joining classNames together
    一个简单的JS工具(可根据状态决定cssName,即动态的cssName)
//  不使用 classnames时:
var Button = React.createClass({
  render () {
    var btnClass = 'btn';
    //根据点击的state来控制css
    if (this.state.isPressed) btnClass += ' btn-pressed';
    else if (this.state.isHovered) btnClass += ' btn-over';
    return ;
  }
});
// 使用classnames时(用法1):
var classNames = require('classnames');

var Button = React.createClass({
  render () {
    var btnClass = classNames({
      'btn': true,
      'btn-pressed': this.state.isPressed,
      'btn-over': !this.state.isPressed && this.state.isHovered
    });
    return ;
  }
});

// 用法2:与 [css-modules](https://github.com/css-modules/css-modules)
配合使用,通过用bind方法可返回样式对象的key
import { Component } from 'react';
import classNames from 'classnames/bind';
import styles from './submit-button.css';

let cx = classNames.bind(styles);

export default class SubmitButton extends Component {
  render () {
    let text = this.props.store.submissionInProgress ? 'Processing...' : 'Submit';//text根据状态来动态加载
    let className = cx({
      base: true,
      inProgress: this.props.store.submissionInProgress,//样式的动态加载
      error: this.props.store.errorOccurred,
      disabled: this.props.form.valid,
    });
    return ;
  }
};
  • reselect
    使用场景:某个状态A依赖其他状态B,但是不希望状态B没有发生变化,但是状态C发生变化时导致状态A被重新计算,这个计算是无效没意义的。这时可以使用 reselect

让我们坐上 Hooks 的托马斯小火车

你可能感兴趣的:(React 技术栈)