0

I'm doing a library project (see the link for more explaination) with react, redux-toolkit and typescript.

I'm doing an addToWishlist funcionality: the user simply click on the star, the code dispatches the action which patch the database and the state is updated. There is another action to remove the book from the list.

In <Wishlist /> component I want of course render the titles and other data of each book. So I useAppSelector to retrieve wishlist and the entire list of books, and with help of filter and map I would get the corresponding books, but I'm not able to render them, because it gives me a ts error: index.d.ts(1373, 9): The expected type comes from property 'children' which is declared here on type 'DetailedHTMLProps<HTMLAttributes<HTMLUListElement>, HTMLUListElement>'

Important note about the structure

wishlist is an array of strings, which are the ids of the books. The entire list of books instead, is an array of objects: every object is a book, with title, author, id etc.

My questions:

  1. What is going wrong here?

  2. Basically, is it better to save in the wishlist array the ids (like I've done) and so I've to retrieve the data of books in my <Wishlist /> component with filter and map, or is it better to save the entire book (or at least, the infos that I need), so that is more easy to have the data?

  3. Which is the best practice, to render the list, in the first case, where I have to retrieve data using filter and map?

Here is the attempt:

const Wishlist = () => {
  const dispatch = useAppDispatch();
  const wishlist = useAppSelector(state => state.user.userInfo.wishlist);
  const list = useAppSelector(state => state.catalogue.list);

  const renderBooks = () => {
    return wishlist.map(wishId => {
      list.filter(book => {
        if (book.id === wishId) {
          return (
            <li>{book.title}</li>
          )
        }
      })
    })
  }

  
  return (
    <ul>
      {renderBooks()}
    </ul>
  )
};

export default Wishlist;

Edited - maybe the problem is not the concatenation of methods, but something in the function calling?

Another more little example, with another solution, but same problem

interface fakeObj {
    id: string;
    name: string;
  }
  const fakeIds = ['5', '12', '878'] // this is my 'wishlist', containing only ids
  const fakeList: fakeObj[] = [ // this is my 'list', containing objects, which were single books
    { id: '334', name: 'Tony' },
    { id: '5', name: 'Milly' },
    { id: '12', name: 'Jack' },
    { id: '7', name: 'Stew' },
    { id: '878', name: 'Mark' },
    { id: '87998', name: 'Greg' }
  ]

  const renderArray = () => {
    const arr: fakeObj[] = []; 
    fakeIds.forEach(id => {
      fakeList.filter(obj => {
        if (obj.id === id) {
          arr.push(obj)
        }
      })
    })
    return arr; // the returned array is what I want: an array continaing the objects that i need
  }

  return (
    <ul>
      {/* The problem actually is here! */}
      {renderArray()} 
    </ul>
  )
ncasteln
  • 109
  • 1
  • 5
  • 2
    First thing you need to understand when to use map and filter and what's the return type of each method. You want to render all the books that have ids in `wishlist`. You first need to filter out the books that contains id in wishlist using filter (that returns book if it satisfies the condition) then use map. `list.filter((book)=> wishlist.includes(book.id)).map((book)=>
  • {book.title}
  • )` [Array Methods Documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array) – Muhammad Nouman Rafique Nov 13 '22 at 02:26
  • I edit my answer to make it more precise regarding the structures, but your method in my case doesn't work, and I'm not sure about the logic. I'll make also an example to understand better. – ncasteln Nov 13 '22 at 16:50