项目作者: ashishkr619

项目描述 :
A running commentary of building chatflix(netflix for group chat) using React & Ably
高级语言: JavaScript
项目地址: git://github.com/ashishkr619/chatflix.git
创建时间: 2020-06-18T13:37:07Z
项目社区:https://github.com/ashishkr619/chatflix

开源协议:

下载


Motivation & Story

Trying to learn react,this is a running commentary of me building chatflix using React & Ably.Chatflix is a place to talk about your favorite neflix shows. The project uses React & Ably’s pub/sub capabilities for realtime communication .

Final Product we are aiming at

The final product we are building in the first version will be a very simple one.Ability to chat into any room(shows) of your choice.One nice feature we will be trying to add in the first version is the ability to react to any particular chat message.
Due to lack of time we will not be adding any database or server side logic as of now.So we will be using Ably’s persist message capability to store all of our chat messages as of now for 24-72 hours.Later we might use Django & Postgres.Images of final product will be updated here everytime we reach one milestone of our development.

Step 1 -Create a new react app & figure out all the components in our App

  1. npm install -g create-react-app #If you don't have react installed on your computer
  2. npx create-react-app chatflix #your fresh new application
  3. cd chatflix #now we are inside chatflix
  4. npm start #fireup the server

Since react is all about breaking webpages into components, lets figure out the components we will be needing ,we might break them up further if required. So inside App.js

RoomList to show us all the rooms/shows we can join
MessageList the actual messaging area
CreateRoom the ability to create new rooms for new shows
SubmitMessageForm the chat submit area

I added the css styles and the ably installations which were pretty easy to do yourself, so no explanation here.

The code until Step 1

Step 2 - Let’s start with the MessageList component

MessageList(or the actual messaging area).To build MessageList we will need to send messages from App.js down to the MessageList Component.To do so we will use props,

  1. <MessageList messages={this.state.messages}></MessageList> // in the App.js

Down in the Messagelist component MessageList.js we receive the list of all messages from App.JS, break them down one by one using map function and further send individual message to Message component

  1. <div className='message-list'>
  2. {this.props.messages.map((message, i) => (
  3. <Message key={i} message={message} ></Message>
  4. ))}
  5. </div>

Inside Message.js
just receive the props and display them

  1. ...
  2. return(
  3. <div className='message'>
  4. <div className='message-text' key={this.props.key}>{this.props.message}</div>
  5. </div>
  6. ...

Let’s send some random messages from App.js to verify our working

  1. ...
  2. constructor(){
  3. super()
  4. this.state={
  5. messages:['hello boss','how are you'], // all the messages
  6. rooms:[], // all the rooms
  7. }
  8. }
  9. ...

The code until Step 2

Step 3- The SubmitMessgeForm component

Form elements have their own internal states based upon user inputs(eg:when i type something the element needs to keep a track of what i am typing),but since we already know that we want to keep the internal state of an element in this.state,and if we would rather control the content of a component , in the component’s state we get a single source of truth and the application becomes less prone to bugs. So let’s take whatever the user inputs and store them into the this.state

Inside SubmitMessgeForm.js
We listen to whatever user types by adding onChange event listener to our form component, and then update state via the handleChange method.

  1. ...
  2. class SubmitMessageForm extends Component {
  3. constructor(props){
  4. super(props)
  5. this.state ={
  6. message :''
  7. }
  8. this.handleChange = this.handleChange.bind(this)//binds the handleChange to a component's instance
  9. }
  10. handleChange(e){
  11. this.setState({
  12. message :e.target.value
  13. })
  14. }
  15. render() {
  16. console.log(this.state.message)// this confirms that we are now getting form data via this.state,so we can use it anyhow we want,lets use this to update value of the input field
  17. return (
  18. <form className="send-message-form">
  19. <input
  20. type="text"
  21. onChange={this.handleChange}
  22. value={this.state.message}
  23. placeholder="type a message and hit Enter..."
  24. />
  25. </form>
  26. );
  27. }
  28. }
  29. ...

Finally we add onSubmit to our form element to submit our message

  1. ...
  2. handleSubmit(e){
  3. e.preventDefault()
  4. console.log(this.state.message)
  5. //connect to ably and send the actual message(this.state.message) in next step
  6. }
  7. ...

The code until Step 3

Step 4- Sending Message & Displaying Sent Messages (The Concept of Inverse Data Flow in React)

Let’s now connect to Ably and broadcast our message.
In SubmitMessageForm.js we send our message to ably

  1. handleSubmit(e){
  2. e.preventDefault()
  3. console.log(this.state.message)
  4. const messageObject= this.state.message
  5. //connect to ably and send the actual message(this.state.message) in next step
  6. /*global Ably*/
  7. const channel = Ably.channels.get('vikings');
  8. channel.publish('add_comment', messageObject, err => {
  9. if (err) {
  10. console.log('Unable to publish message; err = ' + err.message);
  11. }
  12. });
  13. // Clear input fields
  14. e.target.elements.message.value = '';
  15. }
  16. ...

In App.js
to receive and display messsages we need to do two work

  1. we fetch all previous messages on page reload (so we will use componentdidMount to make the api connection and fetch all messages)
    2.we fetch the message the user is typing and then render on the same the page

2.fetch the message the user is typing and then render on the same the page
We already know that data flows in one direction inside the react app from app.js(parent) to smaller(child) components, but this is a different case, we need the data from SubmitMessageForm (smaller/child component) to App.js(higher/parent component).The App.js then receives the message and send it to MessageList Component so that it can render it.

The Concept of Inverse Data Flow in React
When data flows back from the child component to parent component.

To achieve this we create a function displayMessage in App.js and hook this function into SubmitMessageFormComponet so that on successful message submit ,we instantly catch it and re-render it on the ui

Inside App.js

  1. displayMessage(message){
  2. // get the single message,concat to list of messages
  3. this.setState({
  4. messages:[...this.state.messages,message] // a way of concating
  5. })
  6. }
  7. or another way to write
  8. displayMessage(message){
  9. // get the single message,concat to list of messages
  10. this.setState(prevState=>{
  11. return{
  12. messages:prevState.messages.concat(message)
  13. }
  14. })
  15. }

Inside

  1. handleSubmit(e){
  2. e.preventDefault()
  3. console.log(this.state.message)
  4. const messageObject= this.state.message
  5. //connect to ably and send the actual message(this.state.message) in next step
  6. /*global Ably*/
  7. const channel = Ably.channels.get('vikings');
  8. channel.publish('add_comment', messageObject, err => {
  9. if (err) {
  10. console.log('Unable to publish message; err = ' + err.message);
  11. }
  12. else{
  13. // on successful submission to ably instantly update the ui(the hook)
  14. this.props.displayMessage(messageObject)
  15. }
  16. });
  17. // Clear input fields
  18. e.target.elements.message.value = '';
  19. }

1.fetch all previous messages on page reload (so we will use componentdidMount to make the api connection and fetch all messages)

  1. componentDidMount() {
  2. /*global Ably*/
  3. const channel = Ably.channels.get('persistedmessage:vikings');
  4. channel.attach();
  5. channel.once('attached', () => {
  6. channel.history((err, page) => {
  7. // create a new array with comments only in an reversed order (i.e old to new)
  8. const messages = Array.from(page.items, item => item.data)
  9. this.setState({messages });
  10. });
  11. });
  12. }

The code until Step 3