深入浅出React和Redux——阅读笔记7

第七章 Redux和服务器通信

  1. React中的代理


    深入浅出React和Redux——阅读笔记7_第1张图片
    image.png

    深入浅出React和Redux——阅读笔记7_第2张图片
    image.png
  2. 核实发起请求


    深入浅出React和Redux——阅读笔记7_第3张图片
    image.png
  3. fetch
    参考mdn:
    https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API/Using_Fetch

  1. Redux 访问服务器
  • redux-thunk 中间件


    image.png

    深入浅出React和Redux——阅读笔记7_第4张图片
    image.png

    使用,引入文件,并加入到middlewares数组中即可。


    image.png

实例:
store.js中引入redux-thunk

import {createStore, combineReducers, applyMiddleware, compose} from 'redux';

import thunkMiddleware from 'redux-thunk'

import {reducer as weatherReducer} from './weather/';

import Perf from 'react-addons-perf'

const win = window;
win.Perf = Perf

const reducer = combineReducers({
  weather: weatherReducer
});

const middlewares = [thunkMiddleware];
if (process.env.NODE_ENV !== 'production') {
  middlewares.push(require('redux-immutable-state-invariant')());
}

const storeEnhancers = compose(
  applyMiddleware(...middlewares),
  (win && win.devToolsExtension) ? win.devToolsExtension() : (f) => f,
);

export default createStore(reducer, {}, storeEnhancers);

action的类型actionTypes.js

export const FETCH_STARTED = 'WEATHER/FETCH_STARTED';
export const FETCH_SUCCESS = 'WEATHER/FETCH_SUCCESS';
export const FETCH_FAILURE = 'WEATHER/FETCH_FAILURE';

actions.js

import {FETCH_STARTED, FETCH_SUCCESS, FETCH_FAILURE} from './actionTypes.js';

export const fetchWeatherStarted = () => ({
  type: FETCH_STARTED
});

export const fetchWeatherSuccess = (result) => ({
  type: FETCH_SUCCESS,
  result
})

export const fetchWeatherFailure = (error) => ({
  type: FETCH_FAILURE,
  error
})

export const fetchWeather = (cityCode) => {
  return (dispatch) => {
    const apiUrl = `/data/cityinfo/${cityCode}.html`;

    dispatch(fetchWeatherStarted())

    return fetch(apiUrl).then((response) => {
      if (response.status !== 200) {
        throw new Error('Fail to get response with status ' + response.status);
      }

      response.json().then((responseJson) => {
        dispatch(fetchWeatherSuccess(responseJson.weatherinfo));
      }).catch((error) => {
        dispatch(fetchWeatherFailure(error));
      });
    }).catch((error) => {
      dispatch(fetchWeatherFailure(error));
    })
  };
}

reducer.js

import {FETCH_STARTED, FETCH_SUCCESS, FETCH_FAILURE} from './actionTypes.js';
import * as Status from './status.js';

export default (state = {status: Status.LOADING}, action) => {
  switch(action.type) {
    case FETCH_STARTED: {
      return {status: Status.LOADING};
    }
    case FETCH_SUCCESS: {
      return {...state, status: Status.SUCCESS, ...action.result};
    }
    case FETCH_FAILURE: {
      return {status: Status.FAILURE};
    }
    default: {
      return state;
    }
  }
}

视图层,选择城市并派发一个初始城市

import React, {PropTypes} from 'react';
import {connect} from 'react-redux';

import {actions as weatherActions} from '../weather/';

const CITY_CODES = {
  '北京': 101010100,
  '上海': 101020100,
  '广州': 101280101,
  '深圳': 101280601
};



class CitySelector extends React.Component {
  constructor() {
    super(...arguments);

    this.onChange = this.onChange.bind(this);
  }

  onChange(ev) {
    const cityCode = ev.target.value;
    this.props.onSelectCity(cityCode)
  }

  componentDidMount() {
    const defaultCity = Object.keys(CITY_CODES)[0];
    this.props.onSelectCity(CITY_CODES[defaultCity]);
  }

  render() {
    return (
      
    );
  }
}

CitySelector.propTypes = {
  onSelectCity: PropTypes.func.isRequired
};

const mapDispatchToProps = (dispatch) => {
  return {
    onSelectCity: (cityCode) => {
      dispatch(weatherActions.fetchWeather(cityCode));
    }
  }
};

export default connect(null, mapDispatchToProps)(CitySelector);

视图层根据请求状态做不同显示
status.js

export const LOADING = 'loading';
export const SUCCESS = 'success';
export const FAILURE = 'failure';

天气视图

import React, {PropTypes} from 'react';
import {connect} from 'react-redux';
import * as Status from './status.js';

const Weather = ({status, cityName, weather, lowestTemp, highestTemp}) => {
  switch (status) {
    case Status.LOADING: {
      return 
天气信息请求中...
; } case Status.SUCCESS: { return (
{cityName} {weather} 最低气温 {lowestTemp} 最高气温 {highestTemp}
) } case Status.FAILURE: { return
天气信息装载失败
} default: { throw new Error('unexpected status ' + status); } } } Weather.propTypes = { status: PropTypes.string.isRequired, cityName: PropTypes.string, weather: PropTypes.string, lowestTemp: PropTypes.string, highestTemp: PropTypes.string }; const mapStateTopProps = (state) => { const weatherData = state.weather; return { status: weatherData.status, cityName: weatherData.city, weather: weatherData.weather, lowestTemp: weatherData.temp1, highestTemp: weatherData.temp2 }; } export default connect(mapStateTopProps)(Weather);

该进actions.js,终止异步

原理:每次请求都会被编号,当存在多次请求时,存在多个局部变量seqId,但是全局的nextSeqId是唯一的,而且总时最后一个,故通过下面的相等判断,总能返回最新一次请求的结果。

import {FETCH_STARTED, FETCH_SUCCESS, FETCH_FAILURE} from './actionTypes.js';

let nextSeqId = 0;

export const fetchWeatherStarted = () => ({
  type: FETCH_STARTED
});

export const fetchWeatherSuccess = (result) => ({
  type: FETCH_SUCCESS,
  result
})

export const fetchWeatherFailure = (error) => ({
  type: FETCH_FAILURE,
  error
})

export const fetchWeather = (cityCode) => {
  return (dispatch) => {
    const apiUrl = `/data/cityinfo/${cityCode}.html`;

    const seqId = ++ nextSeqId;

    const dispatchIfValid = (action) => {
      if (seqId === nextSeqId) {
        return dispatch(action);
      }
    }

    dispatchIfValid(fetchWeatherStarted())

    fetch(apiUrl).then((response) => {
      if (response.status !== 200) {
        throw new Error('Fail to get response with status ' + response.status);
      }

      response.json().then((responseJson) => {
        dispatchIfValid(fetchWeatherSuccess(responseJson.weatherinfo));
      }).catch((error) => {
        dispatchIfValid(fetchWeatherFailure(error));
      });
    }).catch((error) => {
      dispatchIfValid(fetchWeatherFailure(error));
    })
  };
}

你可能感兴趣的:(深入浅出React和Redux——阅读笔记7)