Eu tenho um contêiner de cabeçalho que passa dados de imagem (url, tamanho) para um componente de cabeçalho usando
@connect(state => ({
header: state.header
}))
export default class HeaderContainer extends Component {
/// pass props.header data to child Header which renders image.
}
Então eu tenho outro componente que precisa chamar as ações do cabeçalho para atualizar o estado do cabeçalho. Não usa o estado, apenas dispara ações. Afaik, preciso fazer algo assim:
const { dispatch } = this.props
const actions = bindActionCreators(headerActions, dispatch)
O problema é que this.props.dispatch só parece estar disponível quando você usa o decorador @connect . O segundo componente não está interessado no estado do cabeçalho. Eu realmente preciso usar o conectar aqui ou pode de alguma forma vincular as ações de uma maneira diferente? Parece errado usar @connect se eu não usar os dados.
Não tenho certeza se é um caminho "certo" ou não, mas você pode acessar a loja pelo contexto. Veja o componente Connector
por exemplo:
https://github.com/gaearon/react-redux/blob/master/src/components/createConnector.js
Eu não te sigo. Estou perfeitamente bem para acessar a loja usando @connect. Estou procurando uma maneira de vincular / chamar ações em um componente sem usar @connect.
A função dispatch
é um método da loja. Se você precisar dele em seu componente, mas não quiser usar @connect
, poderá acessar a loja por meio do contexto e usar seu método de envio:
class MyComponent extends Compoenent {
static contextTypes = {
store: React.PropTypes.object.isRequired,
}
render() {
const { dispatch } = this.context.store
const actions = bindActionCreators(headerActions, dispatch)
}
}
Você deve passar o despacho do componente pai, ou a ação já vinculada ao despacho. Essa é _a_ maneira que acredito, o contexto também funciona, embora seja uma solução alternativa
Obrigado por explicar isso! Agora eu entendi.
Você pode passar dispatch
para aquele componente manualmente como um suporte.
Também estou um pouco confuso com este problema.
Se bem entendi, precisamos ter dispatch
disponível por meio de props de um componente (para ser capaz de despachar ações desse componente) ou dar aos criadores de ação já vinculados a dispatch
, de um componente pai. Mas ambas as soluções requerem um componente pai connect
ed para que o envio seja disponibilizado para ele por meio de seus adereços.
Portanto, no final, estamos apenas transferindo nossa dependência de dispatch
para um componente pai. E como você faria isso se não houvesse esse pai connect
ed?
Por exemplo, e se estivéssemos em uma hierarquia profunda de componentes:
Provider
Router
AppContainer
...
...
...
TheComponentThatNeedDispatch
e se nenhum dos pais precisa se conectar ao estado redux?
Ter o envio disponibilizado para um componente como um efeito colateral do uso de connect
parece nos colocar em uma situação em que é um pré-requisito ter um de seu pai connect
ed para ser capaz de dispatch
uma ação. Isso parece estranho, pois não deve haver qualquer correlação entre a habilidade de um componente em dispatch
uma ação e a necessidade de usar connect
para ler do estado redux.
Sei que ainda podemos acessar dispatch
de um contexto de componente (via store.dispatch
), mas como não é a maneira recomendada ...
O que você acha disso?
Obrigado!
Isso parece estranho, pois não deve haver nenhuma correlação entre a capacidade de um componente de despachar uma ação e a necessidade de usar conectar para ler do estado redux.
Por que é estranho? Pense em connect
como “conectar-se ao Redux” e não apenas “conectar-se a uma parte do estado Redux”. Então faz sentido: para ser capaz de dispatch
qualquer componente em si, ou algum seu pai, precisa ser connect()
ed para Redux.
Com a API React Redux atual, não é conveniente conectar-se ao Redux sem também selecionar o estado. Você teria que escrever algo como connect(state => ({}))(MyComponent)
(return empty object). É por isso que estávamos explorando APIs alternativas para ele que tornam dispatch
um cidadão de primeira classe e planejamos adicionar uma API para obter “apenas dispatch
”.
Isso faz sentido?
Pense em conectar como “conectar ao Redux” e não apenas “conectar a uma parte do estado Redux”.
Totalmente faz sentido agora :).
Mal posso esperar para usar a nova API .
Muito obrigado, usar Redux é uma benção!
Isso está disponível em https://github.com/gaearon/react-redux/releases/tag/v0.5.0.
Isso parece ótimo!
@gaearon ei Dan, você pode me dar uma dica sobre como usar bindActionCreators com componentes aninhados:
"AddProduct" - conectado ao redux (veja abaixo)
__ "Lista de produtos"
____ "ProductView".
Quero que o ProductView possa despachar, mas apenas o mestre "Adicionar produto" tem:
function appState(state) {
return {...};
}
export default connect(appState)(AddProduct)
Você pode connect()
o componente aninhado também, ou você pode passar dispatch
para ele como um prop.
obrigado Dan, realmente agradeço sua ajuda. realmente amo redux também!
outra pergunta se eu puder:
posso colocar solicitações de postagem de API do servidor de dentro do próprio redutor?
quando faço POST no banco de dados (mongodb), o item obtém um "_id" que eu gostaria de ter no meu estado redux. o envio deve ser colocado como um retorno de chamada para a solicitação POST?
obrigado
posso colocar solicitações de postagem de API do servidor de dentro do próprio redutor?
Definitivamente não, os redutores devem ser funções puras e livres de quaisquer efeitos colaterais.
quando faço POST no banco de dados (mongodb), o item obtém um "_id" que eu gostaria de ter no meu estado redux. o envio deve ser colocado como um retorno de chamada para a solicitação POST?
Sim.
Consulte este guia: http://rackt.github.io/redux/docs/advanced/AsyncActions.html
obrigado Dan, funciona muito bem (y)
se estou usando a renderização do servidor para, digamos, fazer o usuário atual logar,
posso pular a busca assíncrona da loja e fazê-lo no servidor?
Se eu estiver usando a renderização do servidor para, digamos, obter o usuário atual conectado, posso pular a busca assíncrona da loja e fazê-lo no servidor?
Você pode criar armazenamento no servidor, aguardar a conclusão das ações assíncronas e, em seguida, renderizar.
Veja também http://rackt.github.io/redux/docs/recipes/ServerRendering.html
Provavelmente estou perdendo algo crítico, mas por que não aplicar apenas parcialmente o despacho em todos os criadores de ação durante a inicialização do aplicativo? Então você poderia ligar de qualquer lugar sem se preocupar em como obter uma referência para despachar.
@mpoisot : porque você teria que saber, importar, ligar e distribuir _todo_ criador de ação potencial na inicialização do aplicativo. Entre outras coisas, isso não ajuda em situações como divisão de código.
@markerikson Eu já tenho que conhecer todos os redutores no app init para que possa chamar createStore
. Estou imaginando ligar para bindAllActionCreators(store.dispatch)
na próxima linha.
É verdade que você pode acabar puxando um pouco mais código do que realmente usa. Mas se isso for uma preocupação, não faça assim. Ou divida seus conjuntos de redutores (redutor + criadores de ação + seletores) em pacotes menores e mais focados. Ou apenas vincule alguns criadores de ação.
Existe alguma penalidade de desempenho terrível para fazer isso? Ou de alguma forma leva a um terrível caminho para o inferno da codificação?
@mpoisot : não há realmente nenhum problema de desempenho que eu possa imaginar. No entanto, ele limita a testabilidade e a reutilização.
O uso adequado de connect
resulta em uma abordagem de injeção de dependência leve. Um componente "simples" só sabe que está recebendo alguma função como um suporte e deve chamar essa função quando necessário. Na verdade, não se importa se é um retorno de chamada transmitido diretamente por algum componente pai ou um criador de ação pré-ligada. Isso significa que o componente pode ser reutilizado de maneira direta e também torna o teste muito mais fácil. Por outro lado, fazer algo como importar diretamente a loja resulta em vincular o componente a essa instância e implementação específica da loja, razão pela qual é desencorajado (de acordo com o Redux FAQ: http://redux.js.org/docs/faq/ StoreSetup.html # store-setup-multiple-stores). Se entendi corretamente o que você está perguntando, é basicamente a mesma situação que importar e fazer referência à loja diretamente.
Ah, bom ponto, aplicar despacho parcialmente em criadores de ação seria equivalente a importar a loja como um único, o que é desaprovado. Eu tentei descobrir o porquê e encontrei vários lugares onde Dan Abramov disse que uma loja de singleton é desaprovada devido à renderização do lado do servidor (que a maioria das pessoas nunca usará), mas estranho que ele nunca mencionou o teste (que todos deveriam fazer, ou pelo menos se sentir mal por não fazer).
O que me faz pensar, com certeza você pode criar um objeto singleton de loja cuja loja pode ser atualizada com diferentes lojas para teste? Em vez de exportar diretamente a própria loja, devolva-a por meio de StoreSingleton.getStore()
e altere a loja atual por meio de StoreSingleton.setStore()
. Portanto, em termos de teste, você não estaria preso a uma única instância de uma loja. No entanto, posso ver por que isso não funcionaria em um ambiente de servidor encadeado.
@mpoisot Você acabou de descrever o que Provider / Connect faz. ;)
Freqüentemente, tenho um componente "burro" que um dia precisa ser despachado (ou uma ação pré-limitada). Então, eu o envolvo em conectar, ou talvez passe coisas de um componente que está conectado. Muitas vezes parece que há muita fiação e adereços passando apenas para evitar o envio acessível globalmente. Para mapStateToProps (), há ganhos de desempenho maravilhosos com Provider / connect (). E para reutilizar componentes burros, definitivamente faz sentido extrair lógica de despacho para o componente de ordem superior.
Mas já atingi esse cenário várias vezes para me perguntar por quê. E parece que a resposta é "para que algum dia você possa fazer renderização do lado do servidor". (Por favor me corrija se eu estiver errado).
Agora, connect()
dá-lhe apenas o dispatch
método de Provider
's loja, mas no futuro, talvez isso pode mudar. Podemos adicionar funcionalidade extra, como integração com ferramentas de desenvolvimento para informar qual componente React foi a fonte de uma ação que está sendo disparada, por exemplo. Ou alguém pode fazer um componente que aprimora a loja de outra maneira, levando a loja no contexto, aprimorando-a de alguma forma e, em seguida, passando essa loja aprimorada para a árvore de componentes. Se você vinculou seus criadores de ação a uma loja de singleton, potencialmente estaria chamando o dispatch
errado.
Sim, alguns dos experimentos de "componente / estado encapsulado" que vi funcionam exatamente com essa abordagem. O interessante dessa ideia é que os outros componentes não precisam saber que nada mudou, uma vez que os componentes do wrapper ainda estão apenas capturando this.context.store
e usando seus dispatch
conforme necessário.
Eu estive em ambos os lados disso -
Em meu aplicativo principal, tratamos a loja como um singleton e usamos uma função getStore()
disponível globalmente. Não usamos renderização do lado do servidor. Ainda usamos Provider
e connect
para mapStateToProps
.
Por outro lado, desenvolvi um aplicativo experimental onde envolvo a loja (como @markerikson mencionados) em vários lugares dentro da hierarquia de componentes, e ambos dispatch
e getState
podem mudar em todo o aplicativo, o que significa que eles _têm_ que ser conectados em todo o aplicativo (seja via context
ou props
) e não podem ser únicos.
Dependendo do que você deseja realizar, acho que as coisas da loja de singleton são viáveis, mas pessoalmente estou me afastando disso aos poucos.
Sim. Você certamente _pode_ tratar a loja como um singleton acessível, mas isso o limita, não é considerado idiomático e não vejo nenhuma vantagem real em fazer isso.
Obrigado, ótimo feedback. Alguém pode postar um link mostrando alguns pacotes de loja?
@mpoisot
Aqui está um dos comentários de Dan que ilustra como embrulhar dispatch
pode ser útil:
https://github.com/reactjs/redux/issues/822#issuecomment -145271384
Você pode ter que ler todo o tópico para entender melhor qual é a motivação.
Em particular, observe como dispatch
é empacotado (eu destaquei):
Desculpe por sequestrar este antigo post, pois estou enfrentando uma confusão semelhante, desejando despachar ações sem conectar.
export default class App extends Component {
...
componentDidMount() {
//registering event listener
BackgroundGeolocation.on('location', this.onLocation, this.onError);
}
onLocation(location) {
//wishing to dispatch an action to update variable in store
}
render() {
return (
<Provider store={store}>
<AlertProvider>
<MainNavigator screenProps={{ isConnected: this.state.isConnected }} />
</AlertProvider>
</Provider>
);
}
}
Pelo que entendi, não posso me conectar à loja neste componente porque estamos apenas configurando e passando a loja para Provider
. Como eu possivelmente despacharia uma ação no meu evento onLocation
?
@isaaclem : bem, nesse caso específico, você _têm_ uma referência à loja, então poderia ligar diretamente para store.dispatch(someAction)
.
A outra opção seria reestruturar sua estrutura de componentes de forma que algum componente _dentro_ do <Provider>
faça o comportamento de geolocalização em segundo plano e também possa ser conectado.
Comentários muito úteis
Você pode passar
dispatch
para aquele componente manualmente como um suporte.