2016-06-09 4 views
0

Ich habe die folgende vereinfachte Komponente für ein Dashboard. Das Dashboard-Objekt wird über Requisiten injiziert. Die Aktion handleDeleteDashboard überprüft, ob das Dashboard nicht das letzte verfügbare Dashboard ist. Wenn dies der Fall ist, dürfen Sie es nicht löschen. Für diese Überprüfung benötige ich nrOfDashboards, die ich vom Laden in mapStateToProps bekomme. Also habe ich die Komponente an den Redux-Speicher angeschlossen.Verwendet context.store.getState() in einem onClick-Handler als Anti-Pattern?

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); 

Aber jetzt ist die Komponente in den Laden abonniert und Updates, wenn nrOfDashboards Änderungen (ich weiß, dass ich hier eine shouldComponentUpdate durchführen kann zu verhindern, wenn von dem Wieder Rendering, aber das ist nicht der Punkt). Daher abonniere ich grundsätzlich Änderungen auf nrOfDashboards, obwohl ich diese Informationen nur benötige, wenn ich aktiv auf den Löschen-Button klicke.

Also kam ich mit einer alternativen Lösung, wo ich die Komponente aus dem Speicher und den Zugriff auf den Speicher über Kontext in der Methode 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); 

Dies funktioniert gut für mich und wenn ich mich aktiv auf die Schaltfläche klicken gewährleiste den frischen Zustand aus dem Laden zu bekommen. Jedenfalls habe ich diese Technik noch nie irgendwo gesehen und auch irgendwo gelesen, dass der Zugriff auf den Store nicht außerhalb von mapStateToProps erfolgen sollte. Aber meine Frage ist, ob der direkte Zugriff auf den Store auf Nachfrage ein Anti-Pattern ist und ob ich Code-Beispiel eins besser folgen sollte, wo ich die Component mit dem Store verbinde?

Antwort

1

Ja. Der direkte Zugriff auf das Geschäft gilt als Anti-Pattern. Idiomatische Redux Code verwendet Grund Dependency Injection - connect() und seine mapState() und mapDispatch() Argumente geben Sie die Daten Ihrer Komponente Bedürfnisse und den Verweis auf dispatch und Middleware wie Redux-Thunk Sie Schöpfer Zugriff auf getState() und dispatch() in Ihrer Aktion gibt.

Idealerweise würde Ihre Komponente einfach einen Aktionsersteller senden und die Logik des Aktionserstellers sich darüber sorgen lassen, ob eine echte Aktion tatsächlich ausgeführt wird oder nicht. Also, in Ihrem Fall, das könnte wie folgt aussehen:

// 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)); 
} 

Siehe Redux FAQ Frage zu diesem Thema: http://redux.js.org/docs/FAQ.html#store-setup-multiple-stores