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

Add chat drafts to conversation state. #111

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

loganmhb
Copy link

@loganmhb loganmhb commented May 6, 2017

First of all, thanks for a great-looking app! I'm really looking forward to seeing this grow. I did some work on #92 because it seemed like a nice-sized task to start learning my way around the codebase.

This pull request allows drafts to be stored per conversation instead of keeping the same draft for all conversations, resolving #92. However, it doesn't (yet?) handle drafts in game chats (it ignores them), because those conversations are not stored in the same way as far as I can tell. I'd be happy to work on improving that as well, but I figured I'd go ahead and put this up for feedback first.

Disclaimer: I'm a backend developer by day and I don't have much experience with React/Flow, so if there are rookie mistakes, obvious problems, or you want to take a different approach that feedback is more than welcome. I also haven't figured out how to test against an API server that's not KGS itself, so I haven't tested submission of chat messages.

This allows drafts to be stored per conversation instead of keeping
the same draft for all conversations. However, it doesn't handle
drafts in game chats the same way, because those conversations are
not stored in the same way.
@jkk
Copy link
Owner

jkk commented May 6, 2017

Hi Logan. Thanks for the PR! This is a good start. There are a few things to mention.

First and biggest: the approach you took is to save the draft text into a conversation record after every change to the text input. While this is the simplest, most straight-forward approach, in practice doing it this way can bog down performance. Currently Shin uses a single store for the entire app, and when its state changes, the entire app re-renders from top to bottom. So after each keypress, the entire screen re-renders, not just the message bar.

To fix this, you can use component-local state to store the latest value of the input, and do a rate-limited update to the global conversation state (maybe 'SAVE_CHAT_DRAFT' as a message type). If you wanted to get fancy, you could even create a reusable text input with that feature built-in (value changes as you type, and then runs a debounced callback every X milliseconds).

Sidebar: in the future, we may have components subscribe to only the subset of state they need from the store, so app state changes don't trigger unnecessary render checks everywhere (we do use PureComponent which does not re-render unless props actually change). For most cases (other than inputs), a single top-down data flow is simpler.

Other issues:

  1. Check the browser console for errors and warnings. There are a few.

  2. Remove console.log calls

  3. Bug: if you're in a room and enter text into the message bar, then switch to another room (which you haven't been in yet), the message bar text persists. It does work if you have different text typed into each room's message bar.

  4. There are a few code conventions I'd like to see followed. I'll make inline comments about those

@@ -6,6 +6,7 @@ import type {Conversation} from '../../model';
type Props = {
conversation: ?Conversation,
onSubmit: string => any;
onDraft: string => any;
Copy link
Owner

Choose a reason for hiding this comment

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

Given that this is not used for games, I'd make it optional: onDraft?: string => any

@@ -22,6 +23,13 @@ export default class ChatMessageBar extends Component {
}
}

_onChange(event: SyntheticEvent) {
Copy link
Owner

Choose a reason for hiding this comment

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

The convention we're using in Shin is to use class property arrow functions for event handlers:

_onChange = (event: SyntheticEvent) => {

This convention sets this appropriately, removing the need for bind later on.

@@ -39,6 +52,8 @@ export default class ChatMessageBar extends Component {
className='ChatMessageBar-input'
type='text'
placeholder={placeholder}
value={draft === '' ? null : draft}
onChange={this._onChange.bind(this)}
Copy link
Owner

Choose a reason for hiding this comment

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

see prior comment about arrow functions for event handlers

chatsDisabled: !game.tree
}}
onSubmit={this._onChat} />
onSubmit={this._onChat}
onDraft={()=>{}}
Copy link
Owner

Choose a reason for hiding this comment

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

see previous comment about making onDraft optional, in which case this can be left out

@loganmhb
Copy link
Author

loganmhb commented May 6, 2017

Thanks for the thorough feedback! I'll start taking care of those things.

At a first glance, it looks like storing the input text value in component local state and making onDraft
an optional function that periodically propagates it into the app store might also eliminate the need to treat the game screen text input differently from the chat screen one.

@loganmhb
Copy link
Author

loganmhb commented May 9, 2017

Regarding debouncing -- do you have a preference for adding a dependency (e.g. lodash.debounce) vs sticking a debounce implementation in the utils?

@jkk
Copy link
Owner

jkk commented May 9, 2017

@loganmhb A debounce util function is preferred

@loganmhb
Copy link
Author

I think the latest commit finishes implementing your suggestions. Let me know if there's anything else you notice or would like changed.

@jkk
Copy link
Owner

jkk commented May 10, 2017

thanks, will review when I get a chance

@jkk
Copy link
Owner

jkk commented May 19, 2017

Almost there! A couple issues:

  1. Sending the chat (pressing enter) does not clear it

  2. In the Chat section, enter some text. Navigate to the Watch section, then back to Chat. The text is gone (but comes back if you toggle between rooms)

Code wise it's looking nice. 👍

@hadim hadim added this to the 0.4 milestone Sep 13, 2018
@hadim
Copy link
Collaborator

hadim commented Sep 13, 2018

@loganmhb Could you rebase this PR?

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.

3 participants