5

I'm building my first react application and I've got an issue.

I want to create a simple app where I can click on a book title in a sidebar, and see a summary of the book. I'm getting the book titles and summaries through an API I've defined locally.

Right now, clicking on a book title doesn't do anything. I get an error in red in the console:

index.js:1 Warning: Each child in a list should have a unique "key" prop.

I'm calling my API like so:

  const [viewingId, setViewingId] = useState()
  const [bookList, setBookList] = useState([])
  const [contents, setContents] = useState({})

  useEffect(() => {

    fetch("http://localhost:5000/books")
    .then(res => res.json())
    .then(res => {setBookList(res)})
  }, [])

  const fetchBookSummary = (id) => {
    fetch(`http://localhost:5000/book/${id}`)
    .then(res => res.json())
    .then(res => {
      setContents({...contents, [id]: res[0]})
    })
  }

This is how I'm defining my 'onClick' function:

  const seeSummary = (id) => {
    fetchBookSummary(id)
    setViewingId(id)
  }

And finally, my App renders like this:

  return (
    <div className="App">
      <div className="App-Container">
        <div className="BookList">
          {bookList.map(book => (
            <Node book={book} onClick={() => seeSummary(book.id)} />
          ))}
        </div>

        <div className="SummaryView">
          {contents[viewingId]?.content?.map((summaryData => (
              <Summary summaryData={summaryData}/>
          )))}
        </div>
      </div>
    </div>
  );
}

I used to have just onClick={seeSummary(book.id)}, but I got a "too many re-renders" error...I'm not sure I understand what adding () => did.

I'd like to be able to see the Summary when I click on a book. Any help is appreciated!

1 Answer 1

4

To resolve the React key warning you just need to provide a valid React key to the elements being mapped.

{bookList.map(book => (
  <Node
    key={book.id} // <-- Add a unique key, the book id is good
    book={book}
    onClick={() => seeSummary(book.id)}
  />
))}

When you were just onClick={seeSummary(book.id)} this was invoking the callback immediately, thus causing the render looping. By adding the "() =>" you are declaring an anonymous function to invoke your seeSummary function and pass the specific book id at-the-time the node is clicked.

I don't see any overt issues with the way you've defined your onClick handler other than the fetching book details will take longer than it will take to update the summary id.

const seeSummary = (id) => {
  fetchBookSummary(id); // fetching data
  setViewingId(id); // will update first.
}

I suspect you haven't connected/attached the onClick prop of the Node component to any DOM element, like a button or div, etc... You need to ensure that the onClick prop is actually attached to something a user can interact with.

Example:

const Node = ({ book, onClick }) => (
  <div onClick={onClick}>
    {book.title} - Click me to see summary!
  </div>
);
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.