Passing thoughts project, React.js, hooks

Guys i am stuck at 6 in passing thoughts project. I am unable to see the thought when added.

and this is is the link to my full code

Below is the code part where I think I lost but couldn’t find it exactly where.

 const handleSubmit = (event) => {
    event.preventDefault();
    
     const thought = {
            id: generateId(),
            text: text,
            expiresAt: getNewExpirationTime(),
    };
    
      addThought(thought)
      
    
  }
1 Like

Use props.addThought(thought) instead of just addThought(thought). This is because you pass the function down as a prop.

Also, here is the code you have for the addThought function:

  const addThought = (thought) => {
    setThoughts((thought) => [thought, ...thoughtS]);
  };

Since the argument to the callback-function for setThoughts represents the old state (which is an array) you want to use the spread operator (…) on that same argument. You could change function body to:

 setThoughts((thoughts) => [thought, ...thoughts]);
1 Like

const addThought = setThoughts((thought) => [thought, ...thoughtS]);

Is this what you are saying?

Here is my full code for all the files, the form is isn’t getting updated for whateveri feed into it.
App.js

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( thought => [thought, ...thoughts]);
  };

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

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


AddThoughtsForm.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) {
      event.preventDefault();
      addThought(thought);
}
    setText('');
      
  }

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

thought.js


import React { useEffect } from 'react';

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

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

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


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

utilities.js

 export function getNewExpirationTime() {
  return Date.now() + 15 * 1000;
}

let nextId = 0;
export function generateId() {
  const result = nextId;
  nextId += 1;
  return result;
}

There are a few issues in your handleSubmit function in AddThoughtForm. There is a comma after the thought object (use a semi-colon) and you are not accessing the addThought-prop. Here is my handleSubmit:

  const handleSubmit = (event) => {    
    event.preventDefault();
    if (text.length > 0) {
      const thought = {
        id: generateId(),
        text: text,
        expiresAt: getNewExpirationTime(),
      };
      props.addThought(thought);
      setText('');
    };
  };

When you call addThought(thought) you can change that to props.addThought(thought). Basically access it like you would using class components but without using this keyword. The other option to access props seems to be like what was done in thought.js:

const { thought, removeThought } = props;

Also, look over your addThought function in App. Currently, Your new thought argument to addThought function is named the same as the call-back-argument to setThoughts (which represents all the current thoughts). I think the hint was a little misleading in the exercise on this one. You need to make sure to use the (…) spread syntax on the current thoughts.

Here is my full code if you want to look at it:
Passing Thoughts

4 Likes

thanks @mike7127143742

Hello, i need some help find what might be causing my app not to work, i compared my code with some of the codes here on the forum but still not sure why my app is not working at all.

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();
    if (text.length > 0) {
    const thought = {
      id: generateId(),
      text: text,
      expiresAt: getNewExpirationTime()
    };
    props.addThought(thought);
    setText('');
    };
  };

  return (
    <form className="AddThoughtForm">
      <input
        value={text}
        onChange={handleTextChange}
        onSubmit={handleSubmit}
        type="text"
        aria-label="What's on your mind?"
        placeholder="What's on your mind?"
      />
      <input type="submit" value="Add" />
    </form>
  );
}
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((thoughts) => [thought, ...thoughts]);
  };

  const removeThought = (thoughtIdToRemove) => {
    setThoughts((thoughts) => thoughts.filter((thought) => 
       thought.id !== thought.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'));
Thought.js
import React, {useEffect} from 'react';

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

  const timeRemaining = thought.expiresAt - Date.now();

  useEffect(() => {
    const timeoutId = setTimeout(() => {
      removeThought(thought.id)
    }, timeRemaining );
    return () => {
      clearTimeout(timeoutId)
      };
  }, [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>
  );
}

Take the “onSubmit” prop off of input and place it on the actual form tag. That should help with making the functionality work.

@glennlaw Thank you, it worked perfect! The only thing i am still checking is why niether the thoughts delete after 15 second or i cant delete them when clicked the bottom

1 Like

I can’t get mine to update at all, this is my code:

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((thoughts) => [thought, ...thoughts]);
  };

  const removeThought = (thoughtIdToRemove) => {
    setThoughts((thoughts) => thoughts.filter((thought) => 
       thought.id !== thought.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'));

AppThoughtForm.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();
    if (text.length > 0) {
    const thought = {
      id: generateId(),
      text: text,
      expiresAt: getNewExpirationTime()
    };
    props.addThought(thought);
    setText('');
    };
  };

  return (
    <form className="AddThoughtForm" onSubmit={handleSubmit}>
      <input
        value={text}
        onChange={handleTextChange}
        onSubmit={handleSubmit}
        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;

  const timeRemaining = thought.expiresAt - Date.now();

  useEffect(() => {
    const timeoutId = setTimeout(() => {
      removeThought(thought.id)
    }, timeRemaining );
    return () => {
      clearTimeout(timeoutId)
      };
  }, [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>
  );
}

I can’t add or remove a thought. The buttons just do nothing.
Does anyone know how to fix this?

In your form, you have onSubmit in two places. First under the tag (which is where it should be). But then you also have it under the input field. In the input field you should not have an onSubmit but only your onChange handler (which you have) and link that to your handleTextChange function. However, I don’t think that is the main problem. You are also importing this:

import { Thought } from './Thought';

But your file is called Thoughts.js with an s on the end. So try to change name of the file to Thought.js so the import matches. If that doesn’t work one option would be to use create-react-app and copy over the code into a local project. It would be easier to find import errors and such using VS-Code for some of these more involved React projects. I ended up doing that for this project and it is also good practice setting up local project.

Hi, pardon.

It should have been Thought.js, I just messed up the description lol.
But yeah, I made the changes and it’s still not working.

Somewhere I had to have skipped something or made a fault.
I wish Codecademy had a video walkthrough on this one, as I’m used to React, but React hooks are still a bit confusing for me.

Hi, nevermind.

Got it sorted now. I forgot to pass a prop on the one section.
It’s working now. Thanks for your help!

Hey Andre! Since you’ve figured out the props passing thing, I think I’m having an issue on that! I don’t know if it’s that or if importing/exporting things wrong. I can’t figure what! I think that I’ve done the same thing as you, but you could check on the changes you’ve made? I’ve noticed that on this case, you have called addThought and removeThought with prefixed by props. // is that correct? I’m still unable to add or remove thoughts.

Apps.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((thought) => [thought, ...thoughts])
  }
  
  const removeThought = (thoughtIdToRemove) => {
    setThoughts(thoughts){
      thoughts.filter((t)=>!t.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'));

AppThoughtForm.js

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

export function AddThoughtForm(props) {
  const [text, setText] = useState('')

  const handleTextChange=(e)=>{
    setText(e.target.value);
  }
  const handleSubmit=(e)=>{
    e.preventDefault();
    const thought = {id: generateId(),
    text: text,
    expiresAt: getNewExpirationTime()}
    if (text.length > 0){
      addThought(thought)
    }
    setText('');
  }
    return (
    <form className="AddThoughtForm" onSubmit={handleSubmit}>
      <input
        type="text"
        aria-label="What's on your mind?"
        placeholder="What's on your mind?"
        value={text}
        onChange={handleTextChange}
      />
      <input type="submit" value="Add" />
    </form>
  );
}

Thoughts.js

import React, { useEffect } from 'react';

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

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

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

You can access the props in AppThoughtForm in two ways. One way is to do like what was already done in the Thought component with this line of code (using Object destructuring):

const { thought, removeThought } = props;

Since this was used in the Thought component you can see that thought or removeThought is simply referenced in the Thought component where the prop was passed in. But if you don’t use Object destructuring then you can instead access the props with props.thought or props.removeThought (in this example). So you can apply the same technique in AppThoughtForm when accessing the addThought function as a prop. Either use props.addThought or do the object destructuring.

1 Like

In thought.js:

useEffect(() => {
    let timeRemaining = thought.expiresAt - Date.now();
    let timeoutId = setTimeout(() => {
      alert('Time has passed!');
    }, timeRemaining);
    return () => {
      clearTimeout(timeoutId);
    }
  }, [thought]);

It says to " add [thought] as a dependency so the effect re-runs every time the thought is different." But a thought never changes before it gets deleted, and the cleanup function should be called when the component is unmounted.

1 Like

Hello guys,
I basically finished the project but there is one problem: I cannot add a new thought, I was able at some point but nothing was displayed in it and now it just seems like every time I create a new one it gets automatically deleted!

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((thought)=>[thought,
    ...thoughts]);
  };

  const removeThought = (thoughtIdToRemove) =>{
    setThoughts((thoughts) => thoughts.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'));

THOUGHT.JS

import React, {useEffect} from 'react';

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

  useEffect(()=>{
    const timeRemaining = thought.expiresAt - Date.now();
    const timeout = setTimeout(()=>{
      props.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>
  );
}

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();
    if (text.length>0){
    const thought = {
      id: generateId(),
      text: text,
      expiresAt: getNewExpirationTime()
    };
    props.addThought(thought);
    setText('');
    };
  };

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

Hi I will try to help you,

  1. I think you don’t have to use props in:
    const timeRemaining = thought.expiresAt - Date.now();
    const timeout = setTimeout(()=>{
      props.removeThought(thought.id);
    }, timeRemaining);
    return () =>{
      clearTimeout(timeout);
    };
  }, [thought]);

, because of const { thought, removeThought } = props; at the top

  1. In App.js look at your removeThought function, add at the end ...thoughts in the setter, like you did in addThought().
  2. Again in App.js look at your addThought function, the problem is in the callback, take a closer look at
    setThoughts((thought)=>[thought,
    ...thoughts]);
  };

change it to:

    setThoughts((thoughts)=>[thought,
    ...thoughts]);
  };

Hey Guys I ahve been working with this and after reading all teh discussion still not so cleared to me Why I am not able make it work properly. I hope anybody can help me with this part, I’ll be more than glad

//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((thoughts) => [thought, ...thoughts]);
  };

  const removeThought = (thoughtIdToRemove) => {
    setThoughts((thoughts) => thoughts.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();
    if (text.length > 0) {
    const thought = {
      id: generateId(),
      text: text,
      expiresAt: getNewExpirationTime()
    };
    props.addThought(thought);
    setText('');
    };
  };

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

Thought.js

import React, {useEffect} from 'react';

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

  const timeRemaining = thought.expiresAt - Date.now();

  useEffect(() => {
    const timeoutId = setTimeout(() => {
      removeThought(thought.id)
    }, timeRemaining );
    return () => {
      clearTimeout(timeoutId)
      };
  }, [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>
  );
}

Thank you so much for the help as I was having a very similar problem. This project is very buggy - it didn’t work until I used your code. I followed the video steps and the formatter for weeks and it wouldn’t work.

2 Likes