Redux: ¿Cómo llamar a acciones sin usar @connect?

Creado en 30 jul. 2015  ·  32Comentarios  ·  Fuente: reduxjs/redux

Tengo un contenedor de encabezado que pasa datos de imagen (url, tamaño) a un componente de encabezado usando

@connect(state => ({
  header: state.header
}))
export default class HeaderContainer extends Component {
 /// pass props.header data to child Header which renders image.
}

Luego tengo otro componente que necesita llamar a las acciones del encabezado para actualizar el estado del encabezado. No usa el estado, solo dispara acciones. Afaik, necesito hacer algo como esto:

const { dispatch } = this.props
const actions = bindActionCreators(headerActions, dispatch)

El problema es que this.props.dispatch solo parece estar disponible cuando usa el decorador @connect . El segundo componente no está interesado en absoluto en el estado del encabezado. ¿Realmente necesito usar connect aquí o de alguna manera puede vincular las acciones de una manera diferente? Se siente mal usar @connect si no uso los datos.

question

Comentario más útil

Puede pasar dispatch a ese componente manualmente como un accesorio.

Todos 32 comentarios

No estoy seguro de si es una forma "correcta" o no, pero puede acceder a la tienda a través del contexto. Vea el componente Connector por ejemplo:
https://github.com/gaearon/react-redux/blob/master/src/components/createConnector.js

Yo no te sigo. Estoy perfectamente bien accediendo a la tienda usando @connect. Estoy buscando una forma de vincular / llamar acciones en un componente sin usar @connect.

La función dispatch es un método de la tienda. Si lo necesita en su componente pero no desea usar @connect , entonces puede acceder a la tienda a través del contexto y usar su método de envío:

class MyComponent extends Compoenent {
    static contextTypes = {
        store: React.PropTypes.object.isRequired,
    }

    render() {
         const { dispatch } = this.context.store
         const actions = bindActionCreators(headerActions, dispatch)
    }
}

Debe pasar el envío desde el componente principal o la acción ya vinculada al envío. Esa es la forma en que creo, el contexto también funciona, aunque es una solución

¡Gracias por explicarme esto! Ahora lo entiendo.

Puede pasar dispatch a ese componente manualmente como un accesorio.

También estoy un poco desconcertado por este problema.

Si entiendo correctamente, necesitamos tener dispatch disponibles a través de los accesorios de un componente (para poder enviar acciones desde ese componente) o dar a los creadores de acciones ya vinculados a dispatch , desde un componente padre. Pero ambas soluciones requieren tener un componente principal que sea connect ed para que el envío esté disponible a través de sus accesorios.

Entonces, al final, solo estamos transfiriendo nuestra dependencia de dispatch a un componente principal. ¿Y cómo harías eso si no existiera un padre connect ed?

Por ejemplo, ¿qué pasaría si estuviéramos en una jerarquía profunda de componentes?

Provider
  Router
    AppContainer
     ...
       ...
         ...
           TheComponentThatNeedDispatch

y si ninguno de los padres necesita conectarse al estado redux?

El hecho de que el envío esté disponible para un componente como efecto secundario del uso de connect parece ponernos en una situación en la que es un requisito previo que uno de sus padres sea connect ed capaz de dispatch una acción. Esto se siente extraño ya que no debería haber ninguna correlación entre la capacidad de un componente para dispatch una acción y la necesidad de usar connect para leer desde el estado redux.

Sé que aún podríamos acceder a dispatch desde un contexto de componente (a través de store.dispatch ) pero como no es la forma recomendada ...

¿Qué piensa usted al respecto?

¡Gracias!

Esto se siente extraño, ya que no debería haber ninguna correlación entre la capacidad de un componente para enviar una acción y la necesidad de usar connect para leer desde el estado redux.

¿Por qué es raro? Piense en connect como "conectarse a Redux" y no simplemente "conectarse a una parte del estado de Redux". Entonces tiene sentido: para poder dispatch el componente en sí, o su padre, debe ser connect() ed para Redux.

Con la API actual de React Redux, no es conveniente conectarse a Redux sin seleccionar también el estado. Tendría que escribir algo como connect(state => ({}))(MyComponent) (devolver objeto vacío). Es por eso que estábamos explorando API alternativas que hacen que dispatch sean ciudadanos de primera clase y planeamos agregar una API para obtener “solo los dispatch ”.

¿Esto tiene sentido?

Piense en conectarse como "conectarse a Redux" y no simplemente "conectarse a una parte del estado de Redux".

Tiene mucho sentido ahora :).

No puedo esperar para usar la nueva API .

¡Muchas gracias, usar Redux es una bendición!

¡Esto luce genial!

@gaearon hey Dan, ¿puedes darme un consejo sobre cómo usar bindActionCreators con componentes anidados?

"AddProduct": conectado a redux (ver más abajo)
__ "Lista de productos"
____ "ProductView".

Quiero que ProductView pueda enviar, pero solo el maestro "Agregar producto" tiene:

function appState(state) {
    return {...};
}

export default connect(appState)(AddProduct)

También puede connect() el componente anidado, o puede pasarle dispatch como un accesorio.

gracias Dan, realmente agradezco tu ayuda. realmente amo redux también!

otra pregunta si puedo:
¿Puedo colocar solicitudes de publicación de API del servidor desde el interior del reductor?
cuando publico en la base de datos (mongodb), el elemento obtiene un "_id" que me gustaría tener en mi estado redux. ¿Se debe realizar el envío como devolución de llamada para la solicitud POST?

gracias

¿Puedo colocar solicitudes de publicación de API del servidor desde el interior del reductor?

Definitivamente no, los reductores deben ser funciones puras libres de efectos secundarios.

cuando publico en la base de datos (mongodb), el elemento obtiene un "_id" que me gustaría tener en mi estado redux. ¿Se debe realizar el envío como devolución de llamada para la solicitud POST?

Si.

Consulte esta guía: http://rackt.github.io/redux/docs/advanced/AsyncActions.html

gracias Dan, funciona muy bien (y)

si estoy usando la representación del servidor para digamos que el usuario actual ha iniciado sesión,
¿Puedo omitir la recuperación asíncrona de la tienda y hacerlo en el servidor?

Si estoy usando la representación del servidor para, digamos, que el usuario actual haya iniciado sesión, ¿puedo omitir la recuperación asíncrona de la tienda y hacerlo en el servidor?

Puede crear una tienda en el servidor, esperar a que finalicen las acciones asíncronas y luego renderizar.
Véase también http://rackt.github.io/redux/docs/recipes/ServerRendering.html

Probablemente me esté perdiendo algo crítico, pero ¿por qué no aplicar el envío parcialmente a todos los creadores de acciones durante la inicialización de la aplicación? Luego, podría llamar desde cualquier lugar sin preocuparse por cómo obtener una referencia para enviar.

@mpoisot : porque tendrías que conocer, importar, vincular y distribuir _todos_ los posibles creadores de acciones al iniciar la aplicación. Entre otras cosas, eso no ayuda en situaciones como la división de código.

@markerikson Ya tengo que conocer todos los reductores en el inicio de la aplicación para poder llamar a createStore . Me estoy imaginando llamando bindAllActionCreators(store.dispatch) en la siguiente línea.

Es cierto que puede terminar ingresando un poco más de código del que realmente usa. Pero si eso le preocupa, no lo haga de esta manera. O divida sus conjuntos de reductores (reductor + creadores de acción + selectores) en paquetes más pequeños y enfocados. O solo unir algunos creadores de acción.

¿Existe alguna penalización de rendimiento terrible por hacer esto? ¿O de alguna manera conduce por un camino terrible hacia la codificación del infierno?

@mpoisot : no puedo pensar en ningún problema de

El uso adecuado de connect da como resultado un enfoque de inyección de dependencia ligera. Un componente "simple" sólo sabe que se le está dando alguna función como accesorio, y debería llamar a esa función según sea necesario. En realidad, no le importa si se trata de una devolución de llamada transmitida directamente por algún componente principal o un creador de acciones predefinidas. Eso significa que el componente se puede reutilizar de una manera sencilla y también hace que probarlo sea mucho más fácil. Por otro lado, hacer algo como importar directamente la tienda da como resultado vincular el componente a esa instancia e implementación de tienda específica, por lo que no se recomienda (según las preguntas frecuentes de Redux: http://redux.js.org/docs/faq/ StoreSetup.html # store-setup-multiple-stores). Si entiendo correctamente lo que está preguntando, es básicamente la misma situación que importar directamente y hacer referencia a la tienda.

Ah, buen punto, aplicar parcialmente el despacho en creadores de acción sería equivalente a importar la tienda como singleton, lo cual está mal visto. Traté de aprender por qué, y encontré varios lugares donde Dan Abramov dijo que una tienda singleton está mal vista debido a la renderización del lado del servidor (que la mayoría de la gente nunca usará), pero extraño que nunca mencionó las pruebas (que todos deberían hacer, o al menos sentirse mal por no hacerlo).

Lo que me hace pensar, seguramente se puede crear un objeto singleton de tienda cuya tienda se pueda actualizar con diferentes tiendas para probar. En lugar de exportar directamente la tienda, devuélvala a través de StoreSingleton.getStore() y cambie la tienda actual a través de StoreSingleton.setStore() . Entonces, en términos de pruebas, no estaría atado a una sola instancia de una tienda. Sin embargo, puedo ver por qué esto no funcionaría en un entorno de servidor con subprocesos.

@mpoisot Acaba de describir lo que hacen Provider / connect. ;)

A menudo tengo un componente "tonto" que algún día necesita ser enviado (o una acción pre-enlazada). Entonces lo envuelvo en connect, o tal vez le paso cosas desde un componente contenedor que está conectado. A menudo se siente como una gran cantidad de cables y accesorios de paso solo para evitar el envío accesible a nivel mundial. Para mapStateToProps () hay maravillosas ganancias de rendimiento con Provider / connect (). Y para reutilizar componentes tontos, definitivamente tiene sentido extraer la lógica de envío al componente de orden superior.

Pero he llegado a este escenario suficientes veces para preguntarme por qué. Y parece que la respuesta es "para que algún día puedas hacer renderizado del lado del servidor". (Por favor corrígeme si estoy equivocado).

En este momento, connect() sólo le da dispatch método desde Provider 's tienda, pero en el futuro, tal vez eso podría cambiar. Podríamos agregar funcionalidad adicional, como la integración con herramientas de desarrollo para decirle qué componente de React fue la fuente de una acción que se está activando, por ejemplo. O alguien podría crear un componente que mejore la tienda de otra manera al tomar la tienda en contexto, mejorarla de alguna manera y luego pasar esa tienda mejorada al árbol de componentes. Si ha vinculado a sus creadores de acciones a una tienda singleton, potencialmente estaría llamando al dispatch incorrecto.

Sí, algunos de los experimentos de "componente / estado encapsulado" que he visto funcionan exactamente con ese enfoque. Lo ingenioso de esa idea es que los otros componentes no necesitan saber que nada ha cambiado, ya que los componentes envoltorios todavía están tomando this.context.store y usando su dispatch según sea necesario.

He estado en ambos lados de esto

En mi aplicación principal, tratamos la tienda como un singleton y usamos una función getStore() disponible globalmente. No utilizamos la representación del lado del servidor. Todavía usamos Provider y connect para mapStateToProps .

Por otro lado, he creado una aplicación experimental en la que envuelvo la tienda (como @markerikson mencionados) en varios lugares dentro de la jerarquía de componentes, y tanto dispatch como getState pueden cambian en toda la aplicación, lo que significa que _ tienen_ que estar conectados en toda la aplicación (ya sea a través de context o props ) y no pueden ser singletons.

Dependiendo de lo que quieras lograr, creo que las cosas de la tienda singleton son viables, pero personalmente me estoy alejando poco a poco.

Si. Ciertamente, puedes tratar la tienda como un singleton accesible, pero te limita, no se considera idiomático y no veo ninguna ventaja real en hacerlo.

Gracias, excelentes comentarios. ¿Alguien puede publicar un enlace mostrando algún envoltorio de la tienda?

@mpoisot

Aquí está uno de los comentarios de Dan que ilustra cómo envolver dispatch podría ser útil:

https://github.com/reactjs/redux/issues/822#issuecomment -145271384

Es posible que tenga que leer todo el hilo para comprender mejor cuál es la motivación.

En particular, observe cómo se envuelve dispatch (lo he resaltado):

wrappeddispatch

Perdón por secuestrar esta publicación anterior porque estoy enfrentando una confusión similar, deseando enviar una acción sin conectarme.

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

Por lo que tengo entendido, no puedo conectarme para almacenar en este componente ya que solo estamos configurando y pasando la tienda a Provider . ¿Cómo podría enviar una acción en mi evento onLocation ?

@isaaclem : bueno, en ese caso específico, usted _tiene_ una referencia a la tienda, por lo que podría llamar directamente store.dispatch(someAction) .

La otra opción sería reestructurar la estructura de su componente para que algún componente _dentro_ el <Provider> haga el comportamiento de geolocalización en segundo plano, y también podría conectarse.

¿Fue útil esta página
0 / 5 - 0 calificaciones

Temas relacionados

CellOcean picture CellOcean  ·  3Comentarios

ilearnio picture ilearnio  ·  3Comentarios

elado picture elado  ·  3Comentarios

jbri7357 picture jbri7357  ·  3Comentarios

mickeyreiss-visor picture mickeyreiss-visor  ·  3Comentarios