es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Selectores NGRX: selector de fábrica dentro de otro selector sin prop en el método createSelector.

Usando el patrón de selector de fábrica const selectA = (id: número) => createSelector (...), tengo una instancia donde quiero reutilizar este selector dentro de otro selector (que itera a través de una matriz de identificadores) pero no sé el valor a pasar al selector de fábrica al llamar a createSelector.

Entonces tengo un selector que uso siempre que quiero obtener una porción del estado para el componente A.


const selectA = (id: número) =>
createSelector (
selector1.selectEntityMap,
selector2.selectEntityMap,
selector3ById(id),
(
thing1,
thing2,
thing3
) => {
return ...
});

Ahora quiero obtener una lista del componente A para cada elemento en una matriz.


const selectListOfA = (ids: número[]) =>
createSelector (
selectA,
(selectorA) => {
return ids.map((id) => selectorA(id));
});

El problema es selectA, que ahora es un selector de fábrica, espera un parámetro, pero no lo sé al llamar a createSelector.

Puedo hacer que el código se compile creando otra fábrica sobre la fábrica

const selectAFactory = () => selectA;

Y luego haga referencia a la nueva fábrica en el createSelector


const selectListOfA = (ids: número[]) =>
createSelector (
selectAFactory, <<< aquí
(selectorA) => {
return ids.map((id) => selectorA(id));
});

Pero, por supuesto, lo que está sucediendo ahora es que el selector devuelve una lista de MemoizedSelector [].

Este patrón no parece que debería ser tan complicado, ¿la gente no está reutilizando sus selectores de esta manera, qué me estoy perdiendo?

Tags:  ,

Answer

  1. Avatar for davy.ai

    Es posible reutilizar un selector de fábrica dentro de otro selector que itera a través de una matriz de IDs. El problema con la implementación actual es que el selector de fábrica selectA espera un parámetro de ID al llamar a createSelector, pero este ID es desconocido al crear el selector selectListOfA.

    Una solución es crear otra fábrica sobre la fábrica selectA, como esta:

    const selectAFactory = () => selectA;
    

    Entonces, hacer referencia a la nueva fábrica en el createSelector de selectListOfA:

    const selectListOfA = (ids: number[]) =>
        createSelector(
        selectAFactory, 
        (selectorA) => {
            return ids.map((id) => selectorA(id));
        });
    

    Sin embargo, esto devolverá una lista de MemoizedSelector [], ya que cada invocación de selectorA devuelve una nueva función de selector.

    Para solucionar esto, podemos modificar el selector selectListOfA para pasar el parámetro de ID a la fábrica del selector selectA para cada iteración:

    const selectListOfA = (ids: number[]) =>
        createSelector(
        selector1.selectEntityMap,
        selector2.selectEntityMap,
        (state, props) => props.id,  // <-- pasar el parámetro ID como props
        (
            thing1, 
            thing2, 
            id // <-- recibir el parámetro ID como argumento
        ) => {
            const selectorA = selectA(id)(state); // <-- llamar a la fábrica selectA con ID
            return ids.map((id) => selectorA(id));
        });
    

    Ahora, selectListOfA devolverá correctamente una lista de funciones MemoizedSelector que cada una toma un estado de entidad como entrada y devuelve la porción de estado para el componente A.

    En resumen, el uso de un patrón de selector de fábrica para reutilizar selectores puede ser complejo cuando el selector externo necesita pasar parámetros al selector interno. En este caso, podemos crear una nueva fábrica sobre la original para diferir el parámetro de ID hasta más tarde. Luego podemos modificar el selector externo para recibir el parámetro de ID como prop, llamar a la nueva fábrica con el ID y usar la función de selector resultante para cada iteración de la matriz.

Comments are closed.