Skip to content

C24 Possum - React-chatlog - YanYi Chen#19

Open
yan202509 wants to merge 5 commits intoAda-C24:mainfrom
yan202509:main
Open

C24 Possum - React-chatlog - YanYi Chen#19
yan202509 wants to merge 5 commits intoAda-C24:mainfrom
yan202509:main

Conversation

@yan202509
Copy link
Copy Markdown

No description provided.

Copy link
Copy Markdown

@anselrognlie anselrognlie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your implementation looks good overall! Please review my comments, and let me know if you have any questions.

Comment thread src/App.jsx Outdated
<div id="App">
<header>
<h1>Application title</h1>
<h1>Chat between Two Person</h1>
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to update this to at least a hard-coded representation of the conversation title:

<h1>Chat between Vladimir and Estragon</h1>

Comment on lines +30 to +34
id: PropTypes.number.isRequired,
sender: PropTypes.string.isRequired,
body: PropTypes.string.isRequired,
timeStamp: PropTypes.string.isRequired,
liked: PropTypes.bool.isRequired,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The id, sender, body, timeStamp, and liked props are always passed (they're defined explicitly in the data and also provided in the test) so we can (and should) mark them isRequired.

The remaining props were up to you, and the tests don't know about them. As a result, using isRequired would cause a warning when running any tests that only pass the known props. As a result, either leaving the prop not marked isRequired or updating the tests to pass a dummy function is required to avoid the warnings.

If we do leave props marked not isRequired, we should either have logic to avoid using those values if they are missing, or make allowance for using a default value.

import PropTypes from 'prop-types';
import TimeStamp from './TimeStamp';

const ChatEntry = (props) => {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally, I prefer to destructure the props since that helps give a clear picture of the props that are actually used within the component in one place which is actually tied to the implementation (as opposed to the PropTypes, which is more loosely connected, and deprecated in more recent React versions). When accessing values on the props instance directly, we need to look throughout the body of the component to see what fields on props are actually used.

const ChatEntry = (props) => {

const likeButtonClicked = () => {
props.onEachLikeToggle(props.id);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that for any props that aren't required (e.g., onEachLikeToggle), we should check that a value was supplied before trying to use it. For example, trying to call a function reference if the value is undefined will result in an error.

Comment thread src/components/ChatEntry.jsx Outdated
<button className="like">🤍</button>
<p>{props.body}</p>
<p className="entry-time">
<TimeStamp time={props.timeStamp}></TimeStamp>
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that for components that don't expect to be given child markup, rather than explicitly writing the closing tag <TimeStamp></TimeStamp>, we prefer to use the empty tag shorthand <TimeStamp />.

Comment thread src/components/ChatEntry.jsx Outdated
// Replace the outer tag name with a semantic element that fits our use case
<replace-with-relevant-semantic-element className="chat-entry local">
<h2 className="entry-name">Replace with name of sender</h2>
<main className="chat-entry local">
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👀 Note that main can be semantic when used in an appropriate context, but here, it causes a validation issue. We need to keep in mind that the React components that we create eventually become HTML displayed in a browser, and we should ensure that the resulting HTML is valid. There should be only a single main tag on a page, but there will me several ChatEntry components rendered, each of which will have its own main tag.

Rather than using main here, there are two potential semantic tags that would arguably be more appropriate (each which usually recommends including a heading tag h of some level). Prefer to use one of those.

Comment on lines +29 to +38
entries: PropTypes.arrayOf(
PropTypes.shape({
id: PropTypes.number.isRequired,
sender: PropTypes.string.isRequired,
body: PropTypes.string.isRequired,
timeStamp: PropTypes.string.isRequired,
liked: PropTypes.bool.isRequired,
}),
),
onLikeToggle: PropTypes.func,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to the props for ChatEntry, here, we have some props that the tests pass and some they don't. The ones that the tests pass (entries) can be marked required without issue, while marking anything else required would cause warnings. Alternatively, we could update the tests to pass these additional props once we have defined them.

We should remember that if we leave props not required, we should include appropriate logic to check for a value before making use of it (e.g., we shouldn't try to call an optional callback without ensuring we have a function to call!).

});

return (
<ul>
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice use of ul with li to encode the structure of the conversation as a list of chat entries. Since ChatEntry is itself better represented by a non-li semantic tag, if we want to use a list to build the onversation, then wrapping the li around theChatEntry works well.

Note that sine we don't want the bullets from the default list styling to show in our conversation, we would need to add additional style rules to remove them.

const ChatLog = (props) => {
const chatEntryComponents = props.entries.map((message) => {
return (
<li key={message.id}>
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 Good job recognizing that the key value then goes on the li item rather than our ChatEntry. Any tag that's rendered into an array, whether a custom component of our own, or a basic component provided by React, should be given a key value.

import PropTypes from 'prop-types';

const ChatLog = (props) => {
const chatEntryComponents = props.entries.map((message) => {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice use of map to convert from the message data into ChatEntry components. We can perform this mapping storing the result into a variable we use in the JSX result as you did here (components are functions, so we can run JS code as usual before we reach the return, and even sometimes have multiple return statements with different JSX), we could make a helper function that we call as part of the return, or this expression itself could be part of the return JSX, which I often like since it helps me see the overall structure of the component, though it can make debugging a little more tricky. But any of those approaches will work fine.

…for names, change main to article, so main is only with app.jsx
Copy link
Copy Markdown

@anselrognlie anselrognlie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 Thanks for the update. Looks good.

return (
// Replace the outer tag name with a semantic element that fits our use case
<main className="chat-entry local">
<article className="chat-entry local">
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 article is a great choice for a semantic tag, since one of its uses is to represent self-contained, reusable page elements.

background-color: red;
}

li {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 This helps the styling significantly.

Comment thread src/App.jsx
Comment on lines +12 to +13
const user1 = 'Vladimir';
const user2 = 'Estragon';
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than hard coding these names, could we calculate them from the message data? More generally, think about what we might do if there were more than two participants in the conversation (a group chat).

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