Me disculpo si esto es algo que ya se ha aclarado, pero una búsqueda de palabras clave en los problemas no arrojó nada que ayudara.
Si quiero llamar a store.dispatch(someAction)
desde un archivo de componente, ¿cuál es la forma correcta de acceder a la instancia store
?
En este momento tengo lo siguiente, que funciona, pero no estoy seguro de que sea el enfoque correcto:
index.jsx:
...
const store = applyMiddleware(
loggingMiddleware, // log every action
thunk // making API requests from actions
)(createStore)(reducer);
export {
store
};
...
Controls.jsx
import {store} from './index.jsx';
import * as actions from './actions';
...
let clickHandler = function(node, data) {
store.dispatch(actions.nodeClicked(data))
}
export const Controls = React.createClass({
render: function() {
// React component gets rendered, and it passes the clickHandler to a
// function that attaches it to a D3 visualization
}
});
¿Hay algo de malo en exportar / importar la tienda de esta manera? Creo que podría crear los controladores de clic como parte del componente React y llamar a this.context.store
, pero en realidad hay alrededor de una docena de controladores de eventos diferentes que se pasan a la visualización D3, por lo que eso no es realmente práctico en esto. situación.
Consulte https://github.com/rackt/react-redux para obtener un método auxiliar para vincular el envío a sus componentes
Específicamente, de https://redux.js.org/docs/basics/UsageWithReact.html
Cualquier componente envuelto con la llamada connect () recibirá una función de envío como accesorio y cualquier estado que necesite del estado global.
¿Hay algo de malo en exportar / importar la tienda de esta manera?
Esto no funcionará si procesa su aplicación en el servidor porque desea tener una instancia store
por solicitud en el servidor. Es por eso que nunca recomendamos este enfoque en los documentos.
¿Por qué no hacer esto en su lugar?
import { Component } from 'react';
import { connect } from 'react-redux';
import * as actions from './actions';
let createHandlers = function(dispatch) {
let onClick = function(node, data) {
dispatch(actions.nodeClicked(data))
};
return {
onClick,
// other handlers
};
}
class Controls extends Component {
constructor(props) {
super(props);
this.handlers = createHandlers(this.props.dispatch);
}
render() {
// pass this.handlers anywhere you'd like
}
}
export default connect()(Controls);
@gaearon Se ve genial, ¡gracias!
@gaearon En realidad, después de probarlo, undefined
por this.props.dispatch
.
Las partes relevantes de mi código:
import React from 'react';
import {Component} from 'react';
import {connect} from 'react-redux';
import * as vizActions from './vizActions';
import viz from './lib/viz';
let createHandlers = function(dispatch) {
return {
click: function(DOMNode, data) {
// Getting undefined here
dispatch(vizActions.setSelectedNode(data));
}
};
}
class Viz extends Component {
constructor(props) {
super(props);
console.log(this.props.dispatch); // <- Getting undefined here
// Passing the redux dispatch to be used in handlers function
this.handlers = createHandlers(this.props.dispatch);
}
componentDidMount() {
// Create Viz
}
componentDidUpdate() {
// Update Viz Data, passing in this.handlers
}
render() {
return <div id="viz"></div>;
}
};
function mapStateToProps(state) {
return {
// Pass the network used for the viz as a prop
network: state.get('visualization').get('network')
};
}
export const VizContainer = connect(mapStateToProps, vizActions)(Viz);
Sin embargo, después de leer otro número (https://github.com/rackt/redux/issues/239) me di cuenta de que en realidad estoy vinculando mis acciones a this.props
través de connect()
, así que puedo simplemente pase la acción necesaria cuando llamo createHandlers()
. Quizás este no sea el mejor enfoque, pero funciona ahora:
...
let createHandlers = function(action) {
return {
click: function(DOMNode, data) {
// This works now
action(data);
}
};
}
class Viz extends Component {
constructor(props) {
super(props);
// Passing the redux dispatch to be used in handlers function
this.handlers = createHandlers(this.props.setSelectedNode); // passing action creator function
}
...
En realidad, después de probarlo, no estoy definido para this.props.dispatch.
Porque no está ejecutando el código que publiqué. En el código que publiqué connect
no recibió el segundo parámetro. Pasas vizActions
allí. Por eso no obtienes dispatch
. Si elimina vizActions
de connect
call, lo obtendrá.
Sin embargo, ambos enfoques son equivalentes, así que elija lo que mejor le parezca.
: +1: Ok, eso tiene sentido ahora. ¡Gracias por la ayuda!
Un poco tarde para la fiesta, pero respondiendo por si acaso ayuda a alguien más tarde (incluyéndome a mí).
Si se necesita un mapDispatchToProps
(el segundo parámetro pasado para conectarse), agregue explícitamente dispatch
como una de las claves.
const mapDispatchToProps = (dispatch) => {
return {
dispatch,
// ... other custom mapped dispatch functions ...
myFunction: (myParam) => {
dispatch(State.Actions...)
},
}
}
export default connect( mapStateToProps, mapDispatchToProps )(Viz);
Hola. También tengo este problema.
@gaearon , estoy agradecido por tu orientación. He usado sus soluciones, pero no puedo entenderlas ni usarlas.
No sé cómo usar this.handlers
Cuando el usuario hace clic en una tarjeta, envío esa identificación de tarjeta a los componentes de los padres y ejecuto la acción.
import React , { Component } from 'react';
import { Col } from "react-bootstrap";
import { connect } from 'react-redux';
import Home from "../components/Home";
import { fetchHome, asideArticle } from "../actions/index";
let createHandlers = function(dispatch) {
let onClick = function(node, articleId) {
dispatch(asideArticle(articleId))
};
return {
onClick
};
}
class HomeContainer extends Component {
constructor(props) {
super(props);
this.handlers = createHandlers(this.props.dispatch);
console.log('constructor => this.props.dispatch => Result => dispatch is undefined);
}
componentDidMount() {
this.props.fetchHome();
}
render() {
const { homeData, article } = this.props;
//
return (
<Col>
<Home homeData={homeData} asideArticle={(articleId) => asideArticle(articleId) } />
</Col>
);
}
}
const mapStateToProps = state => ({
homeData : state.home,
article: state
});
function loadData(store){
return store.dispatch(fetchHome());
}
export default {
loadData,
component: connect(mapStateToProps, { fetchHome, asideArticle })(HomeContainer)
}
¿Cómo puedo usar this.handlers
y pasar el articleId
después de pasar el evento de clic para pasarlo?
¿Y qué significa el parámetro node
en function(node, articleId)
y qué hace?
@EhsanFahami :
Este es un rastreador de errores, no un sistema de soporte. Para preguntas de uso, use Stack Overflow o Reactiflux donde hay muchas más personas listas para ayudarlo; probablemente obtendrá una mejor respuesta más rápido. ¡Gracias!
Comentario más útil
Esto no funcionará si procesa su aplicación en el servidor porque desea tener una instancia
store
por solicitud en el servidor. Es por eso que nunca recomendamos este enfoque en los documentos.¿Por qué no hacer esto en su lugar?