在onClick处理程序中使用context.store.getState()被视为反模式?

时间:2016-06-09 16:11:59

标签: redux react-redux

我为仪表板提供了以下简化组件。仪表板对象通过道具注入。 handleDeleteDashboard操作检查仪表板是否不是最后一个可用的仪表板。如果是,则不允许删除它。对于这个检查,我需要从mapStateToProps中的商店获得的nrOfDashboards。所以我将Component连接到redux商店。

class Dashboard extends Component {
    constructor(props) {
        super(props);
        this.handleDeleteDashboard = this.handleDeleteDashboard.bind(this);
    }

    handleDeleteDashboard() {
        const { dashboardDeleteAction, dashboard, nrOfDashboards } = this.props;
        if (nrOfDashboards < 2) {
            // NOT Allowed to delete
        } else {
            dashboardDeleteAction(dashboard.id);
        }
    }

    render() {
        const { dashboard } = this.props;
        return (
            <Content>
               <h1>{dashboard.name}</h1>
               <Button onButtonClick={this.handleDeleteDashboard}>Delete</Button>
            </Content>
        );
    }
}
Dashboard.propTypes = {
    dashboard: customPropTypes.dashboard.isRequired,
    nrOfDashboards: PropTypes.number.isRequired
};
function mapStateToProps(state) {
   return {
      nrOfDashboards: selectNrOfDashboards(state)
   }
}
export default connect(mapStateToProps, { dashboardDeleteAction: dashboardActionCreators.dashboardDelete })(Dashboard);

但现在,只要nrOfDashboards发生变化,Component就会订阅商店并进行更新(我知道我可以在这里执行一个shouldComponentUpdate来防止重新渲染,但这不是重点)。所以我基本上订阅了nrOfDashboards的更改,虽然我在主动点击删除按钮时只需要这些信息。

所以我想出了一个替代解决方案,我将Component从商店中断开,并通过handleDeleteDashboard方法中的上下文访问商店。

class Dashboard extends Component {
   constructor(props) {
      ...
   }

   handleDeleteDashboard() {
      const { dashboardDeleteAction, dashboard } = this.props;
      const store = this.context;
      if (selectNrOfDashboards(store.getState()) < 2) {
         // NOT Allowed to delete
      } else {
         dashboardDeleteAction(dashboard.id);
      }
   }    
   render() {
        ...
   }
}
Dashboard.propTypes = {
   dashboard: customPropTypes.dashboard.isRequired,
};
Dashboard.contextTypes = {
   store: PropTypes.object
};
export default connect(null, { dashboardDeleteAction: dashboardActionCreators.dashboardDelete })(Dashboard);

这对我来说很好,每当我主动点击按钮时,我都会确保从商店获得新鲜状态。无论如何,我之前没有在其他地方看过这种技术,也读过一些访问商店的地方不应该在mapStateToProps之外完成。但我的问题是,如果按需直接访问商店是一种反模式,如果我最好应该遵循代码示例一,我将组件连接到商店?

1 个答案:

答案 0 :(得分:1)

是。直接访问商店被认为是反模式。惯用Redux代码使用基本依赖注入 - connect()及其mapState()mapDispatch()参数为您提供组件所需的数据和对dispatch的引用,以及Redux-Thunk等中间件通过动作创建者,您可以访问getState()dispatch()

理想情况下,您的组件只会调度一个动作创建者,让动作创建者逻辑担心是否真正发送一个真实动作。因此,在您的情况下,这可能看起来像:

// action creator
export function deleteDashboard(dashboardID) {
    return (dispatch, getState) => {
        const state = getState();
        const numberOfDashboards = selectNumberOfDashboards(state);

        if(numberOfDashboards >= 2) {
            dispatch({
                type : "DELETE_DASHBOARD", 
                payload : {
                    dashboardID
                }
            });            
        }    
    }
}


// component

handleDeleteDashboard() {
    const {dashboard} = this.props;
    this.props.dispatch(deleteDashboard(dashboard.id));
}

请参阅有关此主题的Redux常见问题解答:http://redux.js.org/docs/FAQ.html#store-setup-multiple-stores