Peço desculpas se isso é algo que já foi esclarecido, mas uma pesquisa por palavra-chave nos problemas não revelou nada que ajudasse.
Se eu quiser chamar store.dispatch(someAction)
de um arquivo de componente, qual é a maneira correta de acessar a instância store
?
No momento, tenho o seguinte, que funciona, mas não tenho certeza se é a abordagem certa:
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
}
});
Há algo de errado em exportar / importar a loja assim? Acho que poderia simplesmente criar os manipuladores de clique como parte do componente React e chamar this.context.store
, mas na realidade há cerca de uma dúzia de manipuladores de eventos diferentes que são passados para a visualização D3, então isso não é muito prático neste situação.
Confira https://github.com/rackt/react-redux para um método auxiliar para vincular o despacho aos seus componentes
Especificamente, em https://redux.js.org/docs/basics/UsageWithReact.html
Qualquer componente empacotado com a chamada connect () receberá uma função de despacho como um suporte e qualquer estado de que precisa do estado global.
Há algo de errado em exportar / importar a loja assim?
Isso não funcionará se você renderizar seu aplicativo no servidor porque deseja ter uma instância store
por solicitação no servidor. É por isso que nunca recomendamos essa abordagem nos documentos.
Por que não fazer isso?
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 Parece ótimo, obrigado!
@gaearon Na verdade, depois de experimentar, estou recebendo undefined
por this.props.dispatch
.
As partes relevantes do meu 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);
No entanto, depois de ler outro problema (https://github.com/rackt/redux/issues/239), percebi que estou vinculando minhas ações a this.props
via connect()
, para que eu possa apenas passe a ação necessária quando eu chamo createHandlers()
. Talvez esta não seja a melhor abordagem, mas funciona agora:
...
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
}
...
Na verdade, depois de experimentar, estou ficando indefinido para this.props.dispatch.
Porque você não está executando o código que postei. No código que postei connect
não recebeu o segundo parâmetro. Você passa vizActions
lá. É por isso que você não ganha dispatch
. Se você remover vizActions
da chamada connect
você o obterá.
Ambas as abordagens são equivalentes, então vá com o que parecer melhor para você.
: +1: Ok, isso faz sentido agora. Obrigado pela ajuda!
Meio atrasado para a festa, mas respondendo para o caso de ajudar alguém mais tarde (inclusive eu).
Se um mapDispatchToProps
for necessário (o segundo parâmetro passado para conectar), adicione explicitamente dispatch
como uma das chaves.
const mapDispatchToProps = (dispatch) => {
return {
dispatch,
// ... other custom mapped dispatch functions ...
myFunction: (myParam) => {
dispatch(State.Actions...)
},
}
}
export default connect( mapStateToProps, mapDispatchToProps )(Viz);
Oi. Eu também tenho esse problema.
@gaearon , agradeço sua orientação. Eu usei suas soluções, mas não consigo entender e usar.
Não sei como usar this.handlers
Quando o usuário clica em um cartão, eu envio a identificação do cartão para os componentes do pai e executo a ação.
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)
}
Como posso usar this.handlers
e passar articleId
depois de passar no evento click para passá-lo?
E o que o parâmetro node
significa no function(node, articleId)
e o que ele faz?
@EhsanFahami :
Este é um rastreador de bug, não um sistema de suporte. Para questões de uso, use Stack Overflow ou Reactiflux onde há muito mais pessoas prontas para ajudá-lo - você provavelmente obterá uma resposta melhor mais rápido. Obrigado!
Comentários muito úteis
Isso não funcionará se você renderizar seu aplicativo no servidor porque deseja ter uma instância
store
por solicitação no servidor. É por isso que nunca recomendamos essa abordagem nos documentos.Por que não fazer isso?