1

In the console it shows me a warning: The entity passed to the selectId implementation returned undefined. You should probably provide your own selectId implementation. The entity that was passed: (2) [{…}, {…}] The selectId implementation: item => item._id. What am I missing?

I try to call the productos with:

const products = useSelector(productSelectors.selectIds)
import { createSlice, createEntityAdapter, createAsyncThunk } from "@reduxjs/toolkit";
import axios from "axios";

//Fetch the businesses to show in the home page
export const fetchProducts = createAsyncThunk(
  'products/fetchProducts',
  async (id, { dispatch }) => {
    return axios.get(`https://api-test-carrinho.herokuapp.com/product/business/${id}`
    ).then(resp => {
      dispatch(addProducts(resp.data))
    })
  }
)

const productsAdapter = createEntityAdapter({
  selectId: (item) => item._id
});

const productsSlice = createSlice({
  name: "products",
  initialState: productsAdapter.getInitialState({ loading: false }),
  reducers: {
    /* addProduct: productsAdapter.addOne, */
    addProducts: productsAdapter.setAll
  },
  extraReducers: {
    [fetchProducts.pending](state){
      state.loading = true
    },
    [fetchProducts.fulfilled](state, { payload }){
      state.loading = false
      productsAdapter.setAll(state, payload)
    }
  }
});

export default productsSlice.reducer;

export const { /* addProduct,  */addProducts } = productsSlice.actions;

export const productSelectors = productsAdapter.getSelectors(
  (state) => state.products
);

export const {
  selectById: selectProductById,
  selectAll: selectAllProducts
} = productSelectors;
Linda Paiste
  • 38,446
  • 6
  • 64
  • 102
João Marcos
  • 63
  • 1
  • 6
  • Is productSelectors.selectIds defined? I see selectById, selectId but no sign of selectIds. – James Jun 01 '21 at 18:53

2 Answers2

1

According to Redux Documentation, useSelector should be a function:

import React from 'react'
import { useSelector } from 'react-redux'

export const CounterComponent = () => {
  const counter = useSelector((state) => state.counter)
  return <div>{counter}</div>
}

So, maybe this will help you:

const products = useSelector(state => state./* however your store is implemented */productSelectors.selectIds)
Shivam Jha
  • 3,160
  • 3
  • 22
  • 36
  • I can see why it's confusing but `productSelectors.selectIds` *is* a function. `productSelectors` is a keyed object of selector functions. It's from [Redux Toolkit](https://redux-toolkit.js.org/api/createEntityAdapter#selector-functions) – Linda Paiste Jun 02 '21 at 03:34
1

Undefined id

I was able to replicate your error message

The entity passed to the selectId implementation returned undefined.

On the first instance of the error what I'm seeing in the console is an array of three products. It is trying to find the ._id property on that array. It thinks the array is a single entity rather than an array of entities. Then it is trying to find the ._id property on numbers like 3 and 0.

What's happening here is that it is treating your response as dictionary of product objects which it isn't. We need to be looking at just the .data property and that's where we'll find the products.

Now this is where it gets confusing, but you actually need resp.data.data instead of resp.data. An axios response has a .data property which contains the JSON. Then inside your JSON you have your own .data property.

Thunk Issues

After I fix that, the products get successfully added to the state by addProducts. But there is still a problem further down in fetchProducts.fulfilled. You will get an error

TypeError: Cannot convert undefined or null to object

Because the payload of your fulfilled action is undefined.

With createAsyncThunk you actually don't need to dispatch anything from the thunk. What you need to do is return the data that you want to have as the payload of your fetchProducts.fulfilled action.

export const fetchProducts = createAsyncThunk(
  "products/fetchProducts",
  async (id) => {
    return axios
      .get(`https://api-test-carrinho.herokuapp.com/product/business/${id}`)
      .then((resp) => resp.data.data);
  }
);
Linda Paiste
  • 38,446
  • 6
  • 64
  • 102