admin管理员组

文章数量:1323209

In following example, how can I disable the button during a geolocation request? In this.props.inProgress isn't set on init, I would like to disable button when getCurrentPosition is requested and enable if RECEIVE_LOCATION is resolved. What is correct approach? Do I to use state and copy props to the GeoButton?

export function getGeolocation() {
  return dispatch => {
    if (navigator.geolocation) {
      navigator.geolocation.getCurrentPosition(function(position) {
        dispatch({
          type: 'RECEIVE_LOCATION',
          coords: {
            latitude: position.coords.latitude,
            longitude: position.coords.longitude,
            inProgress: false,
          },
        });
      });
    }
  }
}
export function geolocation(state={}, action) {
  switch (action.type) {
    case 'RECEIVE_LOCATION':
      var newState = action.coords;

      return newState;
    default:
      return state;
  }
}


class GeoButton extends React.Component {
  constructor(props) {
    super(props);
  }

  findLocation(e) {
    e.preventDefault();
    this.props.dispatch(getGeolocation());
  }
  render() {
    console.log(this.props); // on init geolocation object is empty
    var self = this;
    return (
      <div>
        <button type="button" onClick={this.findLocation} disabled={self.props.geolocation.inProgress}>Get location</button>
      </div>
    )
  }
}

export default connect(state => ({
  geolocation: state.geolocation
}))(GeoButton); // just gives it dispatch()

In following example, how can I disable the button during a geolocation request? In this.props.inProgress isn't set on init, I would like to disable button when getCurrentPosition is requested and enable if RECEIVE_LOCATION is resolved. What is correct approach? Do I to use state and copy props to the GeoButton?

export function getGeolocation() {
  return dispatch => {
    if (navigator.geolocation) {
      navigator.geolocation.getCurrentPosition(function(position) {
        dispatch({
          type: 'RECEIVE_LOCATION',
          coords: {
            latitude: position.coords.latitude,
            longitude: position.coords.longitude,
            inProgress: false,
          },
        });
      });
    }
  }
}
export function geolocation(state={}, action) {
  switch (action.type) {
    case 'RECEIVE_LOCATION':
      var newState = action.coords;

      return newState;
    default:
      return state;
  }
}


class GeoButton extends React.Component {
  constructor(props) {
    super(props);
  }

  findLocation(e) {
    e.preventDefault();
    this.props.dispatch(getGeolocation());
  }
  render() {
    console.log(this.props); // on init geolocation object is empty
    var self = this;
    return (
      <div>
        <button type="button" onClick={this.findLocation} disabled={self.props.geolocation.inProgress}>Get location</button>
      </div>
    )
  }
}

export default connect(state => ({
  geolocation: state.geolocation
}))(GeoButton); // just gives it dispatch()
Share Improve this question edited Nov 23, 2015 at 15:03 rooftop 3,0271 gold badge23 silver badges33 bronze badges asked Nov 22, 2015 at 9:23 luznyluzny 2,4007 gold badges30 silver badges65 bronze badges 2
  • can't u use the inProgress flag? Something like disabled="inProgress" – Radu Commented Nov 22, 2015 at 9:42
  • is it not better to set in constructor state object corresponding to the expected data and when resolved then replace this state with this data? I'm not sure what approach is correct in this case, current solution doesn't work. – luzny Commented Nov 22, 2015 at 10:00
Add a ment  | 

1 Answer 1

Reset to default 9

When doing async in redux, you often need to call dispatch twice. One synchronous, one asynchronous.

Your action should look something like this:

export function getGeolocation() {
  return dispatch => {
    dispatch({ type: 'FETCHING_LOCATION' });
    if (navigator.geolocation) {
      navigator.geolocation.getCurrentPosition((position) => {
        dispatch({
          type: 'RECEIVE_LOCATION',
          coords: {
            latitude: position.coords.latitude,
            longitude: position.coords.longitude
          }
        });
      });
    }
  };
}

And your reducer should look like this. I've tweaked the structure of the state object, to separate the app data from the ui data.

export function geolocation(state = {}, action) {
  switch (action.type) {
    case 'RECEIVE_LOCATION':
      return {
        coords: action.coords,
        inProgress: false
      };
    case 'FETCHING_LOCATION':
      return {
        coords: null,
        inProgress: true
      };
  }
  return state;
}

There's no need to have the inProgress flag set within your action creator. The reducer can derive it from the action type.

本文标签: javascriptHow to disable a button while waiting for redux to resolveStack Overflow