曾经实现过Angular版,这次感觉用了高大上的React却写了更多的代码,需要的配置也更多了,有利有弊吧。

但这个“导航条问题”很有意思,涉及到在Redux中写timer,其实我很困惑,到底如何完美模拟用户的页面加载,

貌似浏览器并没有提供进度API,只能以这样拙劣的方式进行模拟,有兴趣的朋友不妨与我交流。

 

代码附上:

LoadingBar.jsx

import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
 
export class LoadingBar extends Component {
  constructor(props) {
    super(props);
 
    this.state = {
      timer: null,
      style: {
        display: 'none',
        position: 'absolute',
        width: '0%',
        height: '3px',
        backgroundColor: 'blue',
        transition: 'width 400ms ease-out, height 400ms linear'
      }
    };
  }
 
  componentWillReceiveProps(nextProps) {
    if (nextProps.status) {
      let progress = 0;
      this.setState({
        style: Object.assign({}, this.state.style, {
          width: '0%'
        })
      });
 
      let timer = setInterval(() => {
        if (progress <= (100 - nextProps.step)) {
          this.setState({
            style: Object.assign({}, this.state.style, {
              width: `${progress += nextProps.step}%`,
              display: 'block'
            })
          });
        }
      }, nextProps.speed);
 
      this.setState({
        timer: timer
      });
    } else {
      clearInterval(this.state.timer);
 
      this.setState({
        timer: null,
        style: Object.assign({}, this.state.style, {
          width: '100%',
          display: 'none'
        })
      });
    }
  }
 
  render() {
    return (
      <div>
        <div style={this.state.style} className={this.props.className}></div>
        <div style={{ display: 'table', clear: 'both' }}></div>
      </div>
    )
  }
}
 
LoadingBar.propTypes = {
  className: PropTypes.string,
  speed: PropTypes.number,
  step: PropTypes.number,
  status: PropTypes.bool,
}
 
function mapStateToProps(state) {
  return {...state.loading};
}
 
export default connect(mapStateToProps)(LoadingBar)

App.jsx

import LoadingBar from 'LoadingBar';

const App = ({children}) => {
  return (
    <div>
      <LoadingBar speed={5} step={2} />
      {children}
    </div>
  );
};

App.propTypes = {
  children: PropTypes.object
};

export default App;

loadingReducer.js

export default function loading(
  state = {
    status: false
  },
  action = {}
) {
  switch (action.type) {
    case 'SHOW_LOADING':
      return Object.assign({}, state, {
        status: true,
      });
    case 'HIDE_LOADING':
      return Object.assign({}, state, {
        status: false,
      });
    default:
      return state
  }
}

loadingActions.js

export function show() {
  return { type: 'SHOW_LOADING' }
}

export function hide() {
  return { type: 'HIDE_LOADING' }
}

loadingMiddleware.js

import { show, hide } from './loadingActions';

const defaultTypeSuffixes = ['REQUEST', 'SUCCESS', 'FAILURE']

export default function loadingBarMiddleware(config = {}) {
  const typeSuffixes = config.typeSuffixes || defaultTypeSuffixes;

  return ({ dispatch }) => next => action => {
    next(action);

    if (action.type === undefined) {
      return;
    }

    const [PENDING, FULFILLED, REJECTED] = typeSuffixes;

    const isPending = `_${PENDING}`;
    const isFulfilled = `_${FULFILLED}`;
    const isRejected = `_${REJECTED}`;

    if (action.type.indexOf(isPending) !== -1) {
      dispatch(show());
    } else if (action.type.indexOf(isFulfilled) !== -1 || action.type.indexOf(isRejected) !== -1) {
      dispatch(hide());
    }
  }
}

配置Store

import { createStore, applyMiddleware } from 'redux';
import { loadingMiddleware } from 'loadingMiddleware';
import rootReducer from './reducers';

const store = createStore(
  rootReducer,
  applyMiddleware(loadingMiddleware())
)

配置RootReducer

import { combineReducers } from 'redux';
import { loadingReducer } from './loadingReducer';

const reducer = combineReducers({
  loading: loadingReducer,
});

 

Posted on 2016-05-26 01:39  向民  阅读(2964)  评论(1编辑  收藏  举报