Wie erhalte ich einen einfachen Versand von this.props mit connect w / Redux?

107

Ich habe eine einfache React-Komponente, die ich verbinde (Zuordnung eines einfachen Arrays / Status über). Um nicht auf den Kontext für das Geschäft zu verweisen, möchte ich eine Möglichkeit haben, den "Versand" direkt von den Requisiten zu erhalten. Ich habe andere gesehen, die diesen Ansatz verwendet haben, aber aus irgendeinem Grund keinen Zugriff darauf haben :)

Hier sind die Versionen jeder npm-Abhängigkeit, die ich derzeit verwende

"react": "0.14.3",
"react-redux": "^4.0.0",
"react-router": "1.0.1",
"redux": "^3.0.4",
"redux-thunk": "^1.0.2"

Hier ist die Komponente mit Verbindungsmethode

class Users extends React.Component {
    render() {
        const { people } = this.props;
        return (
            <div>
                <div>{this.props.children}</div>
                <button onClick={() => { this.props.dispatch({type: ActionTypes.ADD_USER, id: 4}); }}>Add User</button>
            </div>
        );
    }
};

function mapStateToProps(state) {
    return { people: state.people };
}

export default connect(mapStateToProps, {
    fetchUsers
})(Users);

Wenn Sie den Reduzierer sehen müssen (nichts Aufregendes, aber hier ist es)

const initialState = {
    people: []
};

export default function(state=initialState, action) {
    if (action.type === ActionTypes.ADD_USER) {
        let newPeople = state.people.concat([{id: action.id, name: 'wat'}]);
        return {people: newPeople};
    }
    return state;
};

Wenn Sie sehen möchten, wie mein Router mit Redux konfiguriert ist

const createStoreWithMiddleware = applyMiddleware(
      thunk
)(createStore);

const store = createStoreWithMiddleware(reducers);

var Route = (
  <Provider store={store}>
    <Router history={createBrowserHistory()}>
      {Routes}
    </Router>
  </Provider>
);

aktualisieren

Wenn ich meinen eigenen Versand in der Verbindung weglasse (derzeit oben zeige ich fetchUsers), würde ich den Versand kostenlos erhalten (nur nicht sicher, ob ein Setup mit asynchronen Aktionen normalerweise so funktioniert). Mischen sich die Leute oder ist es alles oder nichts?

[mapDispatchToProps]

Toran Billups
quelle

Antworten:

280

Standardmäßig mapDispatchToPropsist nur dispatch => ({ dispatch }).
Wenn Sie also das zweite Argument nicht angeben connect(), werden Sie dispatchals Requisite in Ihre Komponente eingefügt.

Wenn Sie eine benutzerdefinierte Funktion an übergeben mapDispatchToProps, können Sie mit der Funktion alles tun.
Einige Beispiele:

// inject onClick
function mapDispatchToProps(dispatch) {
  return {
    onClick: () => dispatch(increment())
  };
}

// inject onClick *and* dispatch
function mapDispatchToProps(dispatch) {
  return {
    dispatch,
    onClick: () => dispatch(increment())
  };
}

Um Ihnen einige Eingaben zu ersparen, bietet Redux bindActionCreators()Folgendes:

// injects onPlusClick, onMinusClick
function mapDispatchToProps(dispatch) {
  return {
    onPlusClick: () => dispatch(increment()),
    onMinusClick: () => dispatch(decrement())
  };
}

das mögen:

import { bindActionCreators } from 'redux';

// injects onPlusClick, onMinusClick
function mapDispatchToProps(dispatch) {
  return bindActionCreators({
    onPlusClick: increment,
    onMinusClick: decrement
  }, dispatch);
}

oder noch kürzer, wenn Requisitennamen mit den Namen der Aktionsersteller übereinstimmen:

// injects increment and decrement
function mapDispatchToProps(dispatch) {
  return bindActionCreators({ increment, decrement }, dispatch);
}

Wenn Sie möchten, können Sie dispatchdort definitiv von Hand hinzufügen :

// injects increment, decrement, and dispatch itself
function mapDispatchToProps(dispatch) {
  return {
    ...bindActionCreators({ increment, decrement }), // es7 spread syntax
    dispatch
  };
}

Es gibt keinen offiziellen Rat, ob Sie dies tun sollten oder nicht. connect()dient normalerweise als Grenze zwischen Redux-fähigen und Redux-unbewussten Komponenten. Aus diesem Grund halten wir es normalerweise für nicht sinnvoll, sowohl gebundene Aktionsersteller als auch zu injizieren dispatch. Aber wenn Sie das Gefühl haben, dies tun zu müssen, können Sie dies gerne tun.

Schließlich ist das Muster, das Sie gerade verwenden, eine Verknüpfung, die noch kürzer ist als das Aufrufen bindActionCreators. Wenn Sie nur zurückkehren bindActionCreators, können Sie den Anruf weglassen, anstatt Folgendes zu tun:

// injects increment and decrement
function mapDispatchToProps(dispatch) {
  return bindActionCreators({ increment, decrement }, dispatch);
}

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

kann so geschrieben werden

export default connect(
  mapStateToProps,
  { increment, decrement } // injects increment and decrement
)(App);

Sie müssen jedoch auf diese nette kurze Syntax verzichten, wenn Sie etwas Benutzerdefinierteres wünschen, dispatchbeispielsweise auch das Übergeben .

Dan Abramov
quelle
2
@ DanAbramov übrigens ist der zweite Parameter in bindActionCreators(actionCreators, dispatch)optional? Ich habe in Ihrem Code an der // es7 spread syntaxZeile bemerkt , dass der dispatchnicht anbindActionCreators
yonasstephen
Was ist die Inkrementierungsmethode?
Khurshid Ansari
Es7 Spread-Syntax sollte sein function mapDispatchToProps(dispatch) { return { ...bindActionCreators({ increment, decrement }), dispatch }; }
Black
6

Sie können normalerweise basierend auf dem, was Sie möchten, mischen und anpassen.

Sie können passieren dispatchals Stütze auf , wenn das ist , was Sie wollen:

export default connect(mapStateToProps, (dispatch) => ({
    ...bindActionCreators({fetchUsers}, dispatch), dispatch
}))(Users);

Ich bin nicht sicher, wie fetchUserses verwendet wird (als asynchrone Funktion?), Aber Sie würden normalerweise so etwas wie bindActionCreatorsdas automatische Binden des Versands verwenden und müssten sich dann nicht um die dispatchdirekte Verwendung in verbundenen Komponenten kümmern .

Wenn Sie ein dispatchVerzeichnis verwenden, wird die dumme , zustandslose Komponente mit Redux gekoppelt. Was es weniger tragbar machen kann.

Davin Tryon
quelle
3
Was Sie vorschlagen, wird nicht funktionieren. Sie erhalten eine ungebundene fetchUsersInjektion als Requisite. Die Shortcut-Notation funktioniert nur, wenn Sie ein Objekt als zweites Argument übergeben. Wenn Sie eine Funktion übergeben, müssen Sie sich bindActionCreatorsselbst aufrufen : dispatch => ({ ...bindActionCreators({ fetchUsers }, dispatch), dispatch }).
Dan Abramov
Warum direkt in bindActionCreators verbreiten und versenden? dispatch => ( bindActionCreators({ dispatch, fetchUsers }, dispatch))
user3711421
2

Während Sie dispatchals Teil von weitergeben könnten dispatchToProps, würde ich empfehlen, den Zugriff auf storeoder dispatchdirekt von Ihren Komponenten aus zu vermeiden . Es scheint, als wären Sie besser bedient, wenn Sie im zweiten Argument von connect einen gebundenen Aktionsersteller übergebendispatchToProps

Sehen Sie sich ein Beispiel an, das ich hier https://stackoverflow.com/a/34455431/2644281 gepostet habe, wie Sie einen "bereits gebundenen Aktionsersteller" auf diese Weise weitergeben, damit Ihre Komponenten nicht direkt über das Geschäft / den Versand Bescheid wissen oder von diesem abhängen müssen .

Tut mir leid, mich kurz zu fassen. Ich werde mit mehr Infos aktualisieren.

Erik Aybar
quelle