Passing Thoughts Issue

I’ve finished the entire project, but after I complete the final step everything crashes. It displays the ‘alert’ message fine, in step 12, the issue only occurs once I implement step 13.

I’ve read through my code a few times and watched the video to check if I’d missed anything, but I’m still stumped.
I’d just like some help on this bug, so I can move on. Thanks.

Passing Thoughts Project

App.JS

import React, { useState } from 'react';
import ReactDOM from 'react-dom';
import { AddThoughtForm } from './AddThoughtForm';
import { Thought } from './Thought';
import { generateId, getNewExpirationTime } from './utilities';

function App() {
  const [thoughts, setThoughts] = useState([
    {
      id: generateId(),
      text: 'This is a place for your passing thoughts.',
      expiresAt: getNewExpirationTime(),
    },
    {
      id: generateId(),
      text: "They'll be removed after 15 seconds.",
      expiresAt: getNewExpirationTime(),
    },
  ]);

  const addThought = (thought) => {
    setThoughts((prev) => [thought, ...prev]);
  };
  
  const removeThought = (thoughtIdToRemove) => {
    setThoughts((prev) =>{
      prev.filter((thought) => thought.id !== thoughtIdToRemove)
    });
  };

  return (
    <div className="App">
      <header>
        <h1>Passing Thoughts</h1>
      </header>
      <main>
        <AddThoughtForm addThought={addThought} />
        <ul className="thoughts">
          {thoughts.map((thought) => (
            <Thought key={thought.id} thought={thought} removeThought={removeThought} />
          ))}
        </ul>
      </main>
    </div>
  );
}

ReactDOM.render(<App />, document.getElementById('app'));

AddThoughtForm.JS

import React, {useState} from 'react';
import { generateId, getNewExpirationTime } from './utilities';

export function AddThoughtForm(props) {
  const [text, setText] = useState('');
  const handleTextChange = (event) => {
    setText(event.target.value);
  };
  const handleSubmit = (event) => {
    event.preventDefault();
   const thought = {
      id: generateId(),
      text: text,
      expiresAt: getNewExpirationTime(),
    };
  if (text.length > 0) {
    props.addThought(thought);
    setText('');
   }
  };


  return (
    <form className="AddThoughtForm" onSubmit={handleSubmit}>
      <input
        value={text}
        onChange={handleTextChange}
        type="text"
        aria-label="What's on your mind?"
        placeholder="What's on your mind?"
      />
      <input type="submit" value="Add"  />
    </form>
  );
}

Thoughts.JS

import React, {useEffect} from 'react';

export function Thought(props) {
  const { thought, removeThought } = props;

  useEffect(()=>{
      const timeRemaining = thought.expiresAt - Date.now();
      const timeout = setTimeout(() => {removeThought(thought.id)
      }, timeRemaining);
      return () => clearTimeout(timeout);
    }, [thought]);

  const handleRemoveClick = () => {
    removeThought(thought.id);
  };

  
 

  return (
    <li className="Thought">
      <button
        aria-label="Remove thought"
        className="remove-button"
        onClick={handleRemoveClick}
      >
        &times;
      </button>
      <div className="text">{thought.text}</div>
    </li>
  );
}

Double check this function. What I suspect is happening is that the first time a thought is removed, the call to removeThought accidentally sets the thoughts array in state to undefined, so the next time your JSX tries to call .map() on it, an error is raised. Errors like this usually show up in the browser’s console, but I’ve helped a couple people with this project where nothing was reported in the console at all.

The way your function is working right now, the callback isn’t sending the updated array back to state, so it’s being set to undefined instead

Click for another hint

You used { } in your arrow function call to setThoughts(), so you need to use the return keyword.

Had you used it like this

setThoughts((prev) => prev.filter((thought) => thought.id !== thoughtIdToRemove));

Then the value would have been returned automatically

1 Like

Hey, I assume, somewhere is a bug, cause mine removeThought throws an Error. Here is the full code:

import React, { useState } from 'react';
import ReactDOM from 'react-dom';
import { AddThoughtForm } from './AddThoughtForm';
import { Thought } from './Thought';
import { generateId, getNewExpirationTime } from './utilities';

function App() {
  const [thoughts, setThoughts] = useState([
    {
      id: generateId(),
      text: 'This is a place for your passing thoughts.',
      expiresAt: getNewExpirationTime(),
    },
    {
      id: generateId(),
      text: "They'll be removed after 15 seconds.",
      expiresAt: getNewExpirationTime(),
    },
  ]);


  const addThought = (thought) => {
    setThoughts(
      prev => {
        return [thought, ...prev];
      })
  const removeThought = (thoughtIdToRemove) => {
    setThoughts(
      (prev) => prev.filter((thought) =>
      thought.id !== thoughtIdToRemove))
  }

  return (
    <div className="App">
      <header>
        Passing Thoughts
      </header>
      <main>
        <AddThoughtForm addThought={addThought} />
        <ul className="thoughts">
          {thoughts.map((thought) => (
            <Thought key={thought.id} thought={thought} removeThought={removeThought}/>
          ))}
        </ul>
      </main>
    </div>
  );
}

ReactDOM.render(<App />, document.getElementById('app'));

Hello, and welcome to the forums

You didn’t say what the specific error was but double check this block of code

You’re missing a curly brace } to end the block of code for the addThought() method

:woman_facepalming:
makes sense, thanks!