如何在Redux中为每个实例创建一个商店?

时间:2016-08-08 05:31:14

标签: reactjs redux react-redux

有时在Redux应用程序中为每个实例创建一个商店会很有用。 Redux的创建者自己创建了一个Gist,描述了如何实现这一目标:https://gist.github.com/gaearon/eeee2f619620ab7b55673a4ee2bf8400

我已经在Gist中提出了这个问题,但我认为StackOverflow会更好地解决这个问题:

我想知道如何对组件自己的特殊商店进行dispatch操作?有没有办法访问每个store(及其子组件)<Provider />的{​​{1}} - 道具?

例如:我有一些API类从远程服务器获取数据后调用<SubApp />。但由于我无法导入“普通”商店,处理自定义商店以使其可用于其他类/文件/服务的最佳方式是什么?

更新1

所以我得到了它的工作,但我认为这是一种非常肮脏的方式(请注意代码中的dispatch注释):

提供者:

通过在构造函数中创建商店来为每个实例创建一个商店:

UGLY?

集装箱:

提供商为我的export default class OffersGridProvider extends React.Component { constructor(props) { super(props) this.store = createStore(reducers); } render() { return ( <Provider store={this.store}> <OffersGridContainer offers={this.props.offers} /> </Provider> ); } } 注入商店的dispatch方法,我可以使用该方法将操作仅发送到此实例的商店:

OffersGridContainer

API方法:

只需使用我传递的class OffersGridContainer extends React.Component { componentDidMount() { // UGLY??? const { dispatch } = this.props; let destinationIds = []; this.props.offers.forEach((offer) => { offer.to.forEach((destination) => { destinationIds.push(destination.destination); }); }); // MORE UGLY??? destinationsApi.getDestinations(dispatch, destinationIds); } render() { return ( <OffersGridLayout destinations={this.props.destinations} /> ); } } const mapStateToProps = function(store) { return { destinations: store.offersGridState.destinations }; } export default connect(mapStateToProps)(OffersGridContainer); - 方法作为我的API方法的参数:

dispatch

更新2

我们在评论中收到了关于export function getDestinations(dispatch, ids) { const url = $('meta[name="site-url"]').attr('content'); const filter = ids.map((id) => { return `filter[post__in][]=${id}`; }).join('&'); return axios.get(`${url}/wp-json/wp/v2/destinations?filter[posts_per_page]=-1&${filter}`) .then(response => { dispatch(getOffersGridSuccess(response.data)); return response; }); } 的提示,因此我的mapDispatchToProps现在看起来像这样:

Container

更新3(最终答案)

现在一切正常!这是代码:

提供者:

class OffersGridContainer extends React.Component {    
  componentDidMount() {
    let destinationIds = [];

    this.props.offers.forEach((offer) => {
      offer.to.forEach((destination) => {
        destinationIds.push(destination.destination);
      });
    });

    this.props.getDestinations(destinationIds);
  }

  render() {
    return (
      <OffersGridLayout destinations={this.props.destinations} />
    );
  }
}

const mapStateToProps = function(store) {
  return {
    destinations: store.offersGridState.destinations
  };
}

const mapDispatchToProps = function(dispatch) {
  return {
    getDestinations: function(ids) {
      return destinationsApi.getDestinations(dispatch, ids);
    }
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(OffersGridContainer);

集装箱:

export default class OffersGridProvider extends React.Component {    
  constructor(props) {
    super(props)
    this.store = createStore(reducers, applyMiddleware(thunk));
  }

  render() {
    return (
      <Provider store={this.store}>
        <OffersGridContainer offers={this.props.offers} />
      </Provider>
    );
  }
}

API方法:

class OffersGridContainer extends React.Component {
  componentDidMount() {
    const destinationIds = this.props.offers.reduce((acc, offer) => {
      return [...acc, ...offer.to.map(d => d.destination)];
    }, []);

    this.props.getDestinations(destinationIds);
  }

  render() {
    return (
      <OffersGridLayout destinations={this.props.destinations} />
    );
  }
}

const mapStateToProps = function(store) {
  return {
    destinations: store.offersGridState.destinations
  };
}

const mapDispatchToProps = function(dispatch) {
  return {
    getDestinations: function(ids) {
      return dispatch(destinationsApi.getDestinations(ids));
    }
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(OffersGridContainer);

1 个答案:

答案 0 :(得分:1)

我建议您使用redux-thunk包。

,而不是直接在组件中进行api调用

接下来,您应该将mapDispatchToProps函数作为第二个参数传递给connect函数,以将动作创建函数注入组件:

import { getDestinations } from '../actions';

class OffersGridContainer extends React.Component {    
  componentDidMount() {
    // Tip.
    const destinationIds = this.props.offers.reduce((acc, offer) => {
      return [...acc, ...offer.to.map(d => d.destination)];
    }, []);

    // instead `destinationsApi.getDestinations(dispatch, destinationIds)`
    // call action creator function
    this.props.getDestinations(destinationIds);
  }

  render() {
    return (
      <OffersGridLayout destinations={this.props.destinations} />
    );
  }
}

const mapStateToProps = function(store) {
  return {
    destinations: store.offersGridState.destinations
  };
}

const mapDispatchToProps = function(dispatch) {
  return {
    // this function will be available in component as   
    // `this.props.getDestinations`.
    getDestinations: function(destinationIds) {
      dispatch(getDestinations(destinationIds));
    }
  };
}

export default connect(mapStateToProps, mapDispatchToProps)(OffersGridContainer);