-
Notifications
You must be signed in to change notification settings - Fork 117
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Zoisite - Whitney Shake #109
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great work job on react-chatlog! All the tests are passing and you did a nice job implementing the remote/local feature.
A couple things to note - you introduce an unnecessary piece of state that can be refactored away. We should prefer fewer state variables when possible to reduce complexity of our project.
Also called out some commonly followed patterns when writing code in React that would be important to implement the next time around.
Let me know if you have questions about my review comments.
const [chatData, setChatData] = useState(chatMessages); | ||
const [likeCount, setLikeCount] = useState(0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 nice job setting up state for chat messages.
Notice that you create a variable called likeCount
to keep track of state that represents likes. You pass likeCount
to ChatLog as a prop called likeCount
on line 40. However, in ChatLog, the prop likeCount
is never accessed. This means you create state, pass it as a prop and then do not use it.
We can remove line 10 because we do not need likes to be tracked as state. We can simply write a method that counts all the hearts from each chat in chatData
and returns the count. Then you can use this return value to render the heart count.
Something like:
const getHeartCount = () => {
return chatData.reduce((total, chat) => {
return chat.liked ? total + 1 : total;
}, 0)
};
// then on line 33, you can write this:
<h2 className="widget">{getHeartCount()} ❤️s</h2>
const updateChatData = (updatedChat) => { | ||
const entries = chatData.map((entry) => { | ||
if (entry.id === updatedChat.id) { | ||
if (entry.liked !== updatedChat.liked) { | ||
const likeCountChange = updatedChat.liked ? 1 : -1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather than receiving a new entry with it's like status already changed here, rewrite this to accept only an id. The logic about how to copy the message and change the liked status would be better if it was written in App.js, since the state must have all the information necessary to make a new message.
const updateEntryData = id => {
const entries = chatData.map(entry => {
if (entry.id === id){
return {...entry, liked: !entry.liked};
}
else {
return entry;
}
});
setChatData(entries);
}
Also see my above comment about eliminating likeCount as state and creating a separate method for counting likes. When you get rid of likeCount as state, you reduce the complexity of your application.. We've confirmed that likeCount doesn't actually need to be a state since you pass it as a prop but don't use it in the child component. Therefore, you don't need to update the likeCountChange value here. You can just invoke the getHeartCount() method I detailed above
return entry; | ||
} | ||
}); | ||
setChatData(entries); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👀 Since the next version of the chat data depends on the current version, prefer using the callback style of setChatData:
setChatData(prevEntries => (
// logic to use current chats to make a new copy with the desired liked status flipped (the map logic above)
// return the new chats to update the state
))
@@ -7,6 +7,7 @@ describe('Wave 03: clicking like button and rendering App', () => { | |||
// Arrange | |||
const { container } = render(<App />); | |||
let buttons = container.querySelectorAll('button.like'); | |||
console.log(buttons); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remember to remove debugging print statements before opening a PR for review. We want to avoid print statements being committed to the code base to keep it readable and concise
const onHeartClick = () => { | ||
const updatedEntry = { | ||
id: id, | ||
sender: sender, | ||
body: body, | ||
timeStamp: timeStamp, | ||
liked: !liked, | ||
}; | ||
updateChatData(updatedEntry); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See my comment in app.js about only sending updateChatData
an id
as a parameter (instead of a constructed updatedEntry object. That would make onHeartClick() look like:
const onHeartClick = () => {
updateChatData(id);
};
|
||
const ChatEntry = ({sender, body, timeStamp, liked, id, updateChatData}) => { | ||
|
||
const location = sender === 'Vladimir' ? 'local' : 'remote'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👌
<button className="like">🤍</button> | ||
<p>{body}</p> | ||
<p className="entry-time"> | ||
<TimeStamp time={timeStamp}/> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice job passing the correct prop to the provided TimeStamp component 👍
const chatComponents = props.entries.map((entry) => { | ||
return ( | ||
<ChatEntry | ||
key={entry.id} | ||
id={entry.id} | ||
sender={entry.sender} | ||
body={entry.body} | ||
timeStamp={entry.timeStamp} | ||
liked={entry.liked} | ||
updateChatData={props.updateChatData} | ||
/> | ||
); | ||
}); | ||
|
||
return ( | ||
<section> | ||
{chatComponents} | ||
</section> | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of creating a variable chatComponents
to reference the return value from calling map() on props.entries, it's more common to directly iterate over the chat entries in your component like this without using a variable:
const ChatLog = ({entries, heartClick}) => {
return (
<section>
{props.entries.map((entry) => (
<ChatEntry
key={entry.id}
id={entry.id}
sender={entry.sender}
body={entry.body}
timeStamp={entry.timeStamp}
liked={entry.liked}
updateChatData={props.updateChatData}
/>
))}
</section>
)
};
sender: PropTypes.string.isRequired, | ||
body: PropTypes.string.isRequired, | ||
timeStamp: PropTypes.string.isRequired, | ||
liked: PropTypes.bool.isRequired, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Notice that the prop likeCount
that was passed to ChatLog on line 40 in App.js isn't part of PropTypes but also isn't referenced in the rest of this component?
<h1>Application title</h1> | ||
<h1>Chat between Vladimir and Estragon</h1> | ||
<section> | ||
<h2 className="widget" id="heartWidget">{likeCount} ❤️s</h2> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When you write a method that doesn't need likeCount as state, you can just invoke the method getHeartCount()
here between the curly braces
No description provided.