Come ottenere un semplice invio da this.props usando connect w / Redux?


107

Ho un semplice componente React che collego (mappando un semplice array / stato). Per evitare di fare riferimento al contesto per il negozio, vorrei un modo per ottenere "spedizione" direttamente dagli oggetti di scena. Ho visto altri usare questo approccio ma non ho accesso a questo per qualche motivo :)

Ecco le versioni di ciascuna dipendenza npm che sto utilizzando attualmente

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

Ecco il componente con il metodo di connessione

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

Se hai bisogno di vedere il riduttore (niente di eccitante ma eccolo qui)

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

Se hai bisogno di vedere come è configurato il mio router con redux

const createStoreWithMiddleware = applyMiddleware(
      thunk
)(createStore);

const store = createStoreWithMiddleware(reducers);

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

aggiornare

sembra che se ometto il mio invio nella connessione (attualmente sopra sto mostrando fetchUsers), otterrei la spedizione gratuita (solo non sono sicuro se questo è il modo in cui funzionerebbe normalmente una configurazione con azioni asincrone). Le persone si mescolano e si abbinano o è tutto o niente?

[MapDispatchToProps]

Risposte:


280

Per impostazione predefinita mapDispatchToPropsè solo dispatch => ({ dispatch }).
Quindi, se non specifichi il secondo argomento a connect(), verrai dispatchinserito come sostegno nel tuo componente.

Se passi una funzione personalizzata a mapDispatchToProps, puoi fare qualsiasi cosa con la funzione.
Alcuni esempi:

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

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

Per risparmiare un po 'di digitazione Redux fornisce bindActionCreators()che ti consente di trasformare questo:

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

in questo:

import { bindActionCreators } from 'redux';

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

o anche più breve quando i nomi degli oggetti di scena corrispondono ai nomi dei creatori di azioni:

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

Se lo desideri, puoi sicuramente aggiungerlo dispatcha mano:

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

Non ci sono consigli ufficiali sull'opportunità o meno di farlo. connect()di solito funge da confine tra i componenti Redux-aware e Redux-inconsapevoli. Questo è il motivo per cui di solito riteniamo che non abbia senso iniettare sia i creatori di azioni vincolate che dispatch. Ma se senti di doverlo fare, sentiti libero di farlo.

Infine, lo schema che stai usando in questo momento è una scorciatoia ancora più breve della chiamata bindActionCreators. Quando tutto ciò che fai è tornare bindActionCreators, puoi omettere la chiamata così invece di fare questo:

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

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

può essere scritto così

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

Tuttavia dovrai rinunciare a quella bella sintassi breve ogni volta che vuoi qualcosa di più personalizzato, come anche passare dispatch.


2
@DanAbramov btw è il secondo parametro bindActionCreators(actionCreators, dispatch)facoltativo? Ho notato nel tuo codice alla // es7 spread syntaxriga, il dispatchnon è passato abindActionCreators
yonasstephen

cos'è il metodo incrementale interno?
Khurshid Ansari

La sintassi di diffusione di es7 dovrebbe essere function mapDispatchToProps(dispatch) { return { ...bindActionCreators({ increment, decrement }), dispatch }; }
Nero

6

Di solito puoi mescolare e abbinare in base a ciò che desideri.

È possibile passare dispatchcome un puntello, se questo è ciò che si vuole:

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

Io non sono sicuro di come fetchUsersviene utilizzato (come una funzione asincrona?), Ma di solito si usare qualcosa di simile bindActionCreatorsper l'auto-bind spedizione e quindi non avrebbe dovuto preoccuparsi di usare dispatchdirettamente nei componenti collegati.

L'utilizzo del dispatchtipo di directory accoppia il componente stupido e senza stato con redux. Il che può renderlo meno portatile.


3
Quello che stai suggerendo non funzionerà. Otterrai un non legato fetchUsersiniettato come sostegno. La notazione del collegamento funziona solo quando si passa un oggetto come secondo argomento. Quando si passa una funzione devi chiamare bindActionCreatorste stesso: dispatch => ({ ...bindActionCreators({ fetchUsers }, dispatch), dispatch }).
Dan Abramov

Perché diffondere e passare in spedizione direttamente in bindActionCreators? dispatch => ( bindActionCreators({ dispatch, fetchUsers }, dispatch))
user3711421

2

Sebbene tu possa passare dispatchcome parte di dispatchToProps, ti consiglio di evitare di accedere a storeo dispatchdirettamente dall'interno dei tuoi componenti. Sembra che saresti servito meglio passando un creatore di azioni vincolate nel secondo argomento di connectdispatchToProps

Guarda un esempio che ho pubblicato qui https://stackoverflow.com/a/34455431/2644281 di come tramandare un "creatore di azioni già vincolato" in questo modo i tuoi componenti non devono conoscere direttamente o dipendere dal negozio / spedizione .

Mi dispiace essere breve. Aggiornerò con ulteriori informazioni.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.