Skip to content
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

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open

Zoisite - Whitney Shake #109

wants to merge 6 commits into from

Conversation

WhitShake
Copy link

No description provided.

Copy link

@yangashley yangashley left a 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.

Comment on lines +9 to +10
const [chatData, setChatData] = useState(chatMessages);
const [likeCount, setLikeCount] = useState(0);

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>

Comment on lines +13 to +17
const updateChatData = (updatedChat) => {
const entries = chatData.map((entry) => {
if (entry.id === updatedChat.id) {
if (entry.liked !== updatedChat.liked) {
const likeCountChange = updatedChat.liked ? 1 : -1;

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);

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);

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

Comment on lines +12 to +21
const onHeartClick = () => {
const updatedEntry = {
id: id,
sender: sender,
body: body,
timeStamp: timeStamp,
liked: !liked,
};
updateChatData(updatedEntry);
};

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';

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}/>

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 👍

Comment on lines +7 to +25
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>
)

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,

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>

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants