Conversation
audreyandoy
left a comment
There was a problem hiding this comment.
Great work Jamie! Your code passes all the tests, requirements, and was really easy to read! I have included some feedback in your PR. Let me know if you have any questions.
Grade: 🟢
| const toggleHeart = (id) => { | ||
| // count = 0; | ||
| console.log({ id }); | ||
| const newHeartCount = heart.map((message) => { | ||
| if (message.id === id) { | ||
| return { ...message, liked: !message.liked }; | ||
| } | ||
| return message; | ||
| }); | ||
| setHeart(newHeartCount); | ||
| }; |
There was a problem hiding this comment.
Nice work managing the data and returning a brand new object using the spread operator!
Here's a refresher on updating state in React:
React components re-render whenever there is a change/update to state data. In this case, our data is an object and we are modifying values nested within that object.
Under the hood, React uses Object.is() to compare the previous state object with the one that's been provided viasetMessages(updatedMessages). Object.is() checks if the object has changed and more specifically if the object passed has a different reference in memory. In Javascript, changing the properties and/or values in an object does NOT change the object reference, which is why we must create a new version of our state object (contains a copy of all the properties that weren't updated along with the properties/values that were).
Here is an article with more info: https://www.valentinog.com/blog/react-object-is/
| const ChatEntry = (props) => { | ||
| const heartType = props.liked ? '❤️' : '🤍'; | ||
| const handleToggleHeart = () => { | ||
| props.toggleHeartCallback(props.id); | ||
| }; | ||
|
|
||
| return ( | ||
| <div className="chat-entry local"> | ||
| <h2 className="entry-name">Replace with name of sender</h2> | ||
| <h2 className="entry-name">{props.sender}</h2> | ||
| <section className="entry-bubble"> | ||
| <p>Replace with body of ChatEntry</p> | ||
| <p className="entry-time">Replace with TimeStamp component</p> | ||
| <button className="like">🤍</button> | ||
| <p>{props.body}</p> | ||
| <p className="entry-time"> | ||
| <TimeStamp time={props.timeStamp}></TimeStamp> | ||
| </p> | ||
| <button className="like" onClick={handleToggleHeart}> | ||
| {heartType} | ||
| </button> | ||
| </section> | ||
| </div> | ||
| ); | ||
| }; |
There was a problem hiding this comment.
Nice work handling the likes feature. I also like the way you wrote this component, in the sense of, all logic pertaining to data or invoking other functions remain in the 'brains' of the component while the 'beauty' section in the return statement is only in charge of rendering data.
| ChatEntry.propTypes = { | ||
| //Fill with correct proptypes | ||
| id: PropTypes.number, | ||
| sender: PropTypes.string.isRequired, | ||
| body: PropTypes.string.isRequired, | ||
| timeStamp: PropTypes.string.isRequired, | ||
| liked: PropTypes.bool, | ||
| toggleHeartCallback: PropTypes.func.isRequired, | ||
| }; |
| const ChatLog = (props) => { | ||
| const chitChats = props.entries.map((message, index) => { | ||
| return ( | ||
| <ChatEntry | ||
| key={index} | ||
| id={message.id} | ||
| sender={message.sender} | ||
| body={message.body} | ||
| timeStamp={message.timeStamp} | ||
| liked={message.liked} | ||
| toggleHeartCallback={props.toggleHeartCallback} | ||
| ></ChatEntry> | ||
| ); | ||
| }); | ||
| return <div className="chat-log">{chitChats}</div>; | ||
| }; |
There was a problem hiding this comment.
👍 Nice work including the key for sibling components!
| ChatLog.propTypes = { | ||
| entries: PropTypes.arrayOf( | ||
| PropTypes.shape({ | ||
| id: PropTypes.number, | ||
| sender: PropTypes.string.isRequired, | ||
| body: PropTypes.string.isRequired, | ||
| timeStamp: PropTypes.string.isRequired, | ||
| liked: PropTypes.bool, | ||
| }) | ||
| ).isRequired, | ||
| toggleHeartCallback: PropTypes.func, | ||
| }; |
There was a problem hiding this comment.
Nice work setting up the propTypes for validating the array's nested objects.
| const HeartCount = (messages) => { | ||
| let count = 0; | ||
| messages.forEach((m) => (m.liked ? count++ : m)); | ||
| return <div>{count} ❤️s</div>; | ||
| }; | ||
| export default HeartCount; |
| { | ||
| /* Wave 01: Render one ChatEntry component | ||
| Wave 02: Render ChatLog component */ | ||
| <ChatLog entries={heart} toggleHeartCallback={toggleHeart}></ChatLog> |
There was a problem hiding this comment.
Because ChatLog doesn't contain any child components, we can change it to a self-closing tag.
<ChatLog entries={heart} toggleHeartCallback={toggleHeart} />There was a problem hiding this comment.
Here's more info on when to use self-closing tags: https://stackoverflow.com/questions/48991212/react-component-closing-tag
|
|
||
| const toggleHeart = (id) => { | ||
| // count = 0; | ||
| console.log({ id }); |
There was a problem hiding this comment.
When you're working with teams you'll want your PR's to only contain code your teammates should 'pull' as part of the codebase. Code that's meant to test features in local environments such as print statements or console logs can all be removed, or kept in a local branch.
No description provided.