容器组件、UI组件和无状态组件

  容器组件:处理数据

  UI组件:处理视图

  无状态组件 纯净的render

 异步请求

  componentDidMount中执行ajax请求

async componentDidMount(){
  let {status, data:{data}} = await axios.get('/api/data.json')
  if (status === 200) {
    store.dispatch(initListAction(data))
  }
}

Redux-thunk中间件实现Ajax

npm install redux-thunk

配置  

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

// Note: this API requires redux@>=3.1.0
const store = createStore(
  rootReducer,
  applyMiddleware(thunk)
);

  因为我们使用了Redux devtool插件

  配置修改为

import { createStore, compose, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import reducer from './reducer';

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose
const store = createStore(reducer, composeEnhancers(
    applyMiddleware(thunk)
))

export default store;

  接下来修改Ajax请求

  首先在createAction.js添加Ajax请求,使用thunk可以返回一个函数

export const  getTodoList =  () => {
  return async dispatch => {
    let {status, data:{data}} = await axios.get('/api/data.json')
    if (status === 200) {
      const action = initListAction(data)
      dispatch(action)
    }
  }
}

  在Component   action会接收getTodoList函数,调用dispatch如果发现action不是对象而且是函数会自动执行,即getTodoList

 const action = getTodoList()
 store.dispatch(action)

  我们可以看出使用thunk是对dispatch的一次升级 dispatch不光可以接受对象还可以接受函数,如果接受函数会自动执行

Redux-saga中间件实现Ajax  

npm install --save redux-saga

  在index.js配置如下 引入redux-saga

import { createStore, compose, applyMiddleware } from 'redux'
import createSagaMiddleware from 'redux-saga'
import reducer from './reducer'
import saga from './saga'

const sagaMiddleware = createSagaMiddleware()

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose
const store = createStore(reducer, composeEnhancers(
    applyMiddleware(sagaMiddleware)
))
sagaMiddleware.run(saga)

export default store

  创建saga.js

function* mySaga() {
}

export default mySaga;

  在组件Component组件store.dispatch(action) ,saga会通过takeEvery捕获,然后执行 generator

function*  getInitList() {
  try {
    let {status, data:{data}} = yield axios.get('/api/data.json')
    if (status === 200) {
      const action = initListAction(data)
      yield put(action)
    }
  } catch (error) {
  }
}

function* mySaga() {
  yield takeEvery(types.GET_INIT_LIST, getInitList)
}

export default mySaga;

react-redux

npm install --save react-redux

  首先在src->Index.js引入 然后把store挂载上去,让App其他Component都能使用store能力

import {Provider} from 'react-redux'
import store from './store'
const App = (
  <Provider store={store}>
    <TodoList />
  </Provider>
)

  在Component组件引入react-redux的connect 将store和Commponent连接起来

  connect有2个参数

    mapStateToprops 是state到Component的props的映射

    mapDispatchToProps 定义了用户操作action,改变state的值

onst mapStateToprops = state => {
  return {}
}
const mapDispatchToProps = dispatch => {
  return {}
}
export default connect(mapStateToprops, mapDispatchToProps)(TodoList)

使用combineReducers拆分数据管理

  修改store下reducer.js代码,拆分数据

import { combineReducers } from 'redux'
import {reducer as headerReducer }  from '../common/header/store'

export default combineReducers({
  header: headerReducer
})

使用immutable和redux-immutable

  非常安全的修改state中数据

  配置

  reducer.js

import { combineReducers } from 'redux-immutable'
const defaultState = fromJS({
  city: '上海'
})
常用的方法:

1:fromJS  把一个普通对象改变成一个immutable对象

2set  immutable对象的set方法,会结合之前immutable对象的值和设置的值,返回一个新的对象  使用如下: state.set('focused',true);

3get :  get() 、 getIn()  可以用来获取数据 如下使用:  state.getIn(['header','list'])  等价于state.get('header').get('focused')

4:merge(浅合并,新数据与旧数据对比,旧数据中不存在的属性直接添加,就数据中已存在的属性用新数据中的覆盖)  

  merge使用如下:

 state.merge({
    list:action.data,
    totalPage:action.totalPage
})
5:更新数组 update('chat', item=>item.concat(action.data))

使用styled-components  

  css in js类库,非常适合react

react-router-dom  

核心代码片段 

  <BrowserRouter>
    <div>
      <Header/>
      <Route path="/" exact component={Home}/>
      <Route path="/detail/:id" exact component={Detail}/>
    </div>
  </BrowserRouter>

  获得pathname

    const {pathname} = this.props.location

  页面跳转

    this.props.history.push('/')

  页面重定向

    <Redirect from='/...' to='/...' />

react-loadable 

  异步加载组件

yarn add react-loadable

  如何使用?比如我们在detail组件下新建loadable.js

  loader 是加载当前目录下index.js 是异步加载语法

  loading 进入detail组件需要时间,可以在页面显示临时内容 

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

const LoadableComponent = Loadable({
  loader: () => import('./'),
  loading: Loading,
});

export default class App extends React.Component {
  render() {
    return <LoadableComponent/>;
  }
}

  于是detail就是异步组件了  

  接下来修改detail路由

import Detail from './pages/detail/loadable.js'

   此时会出现问题  

    TypeError: Cannot read property 'params' of undefined 

  因为加载的是异步组件,所以不能直接获取路由里面的内容,params

  可以使用widthRouter方法,让detail有能力获得路由参数

export default connect(mapState, mapDispatch)(withRouter(Detail))

Fragment的使用

  将多个元素集合在一起,不会产生新的DOM

PureComponent的使用
  会提升性能, 为你提供一个浅比较的shouldComponentUpdate方法,其他和Component一样。
  也就是说当state和props发生变化时,PureComponent会将state和props进行浅比较,数据发生变化才render。Component是直接render
  可以提升性能,但是也有潜在的风险。
  不过可以使用immutable管理state

Purerendermixin

  这也是一个对shouldComponentUpdate优化方案

  

posted on 2018-12-07 08:32  苏荷酒吧  阅读(207)  评论(0编辑  收藏  举报