By: Jay Hayes https://iamvery.com https://twitter.com/iamvery
You're about to build a chat room. Cool!
-
Make the
Topics
component display topics dynamically by injecting data as a property.-let Topics = () => +let Topics = ({topics}) => <div> <h4>Click on a topic...</h4> <ul> - <li><a href="#">baseball</a></li> - <li><a href="#">student loans</a></li> + {topics.map(topic => <li><a href="#">{topic}</a></li>)} </ul> </div> // ... class App extends React.Component { + constructor(props) { + super(props) + this.state = {topics: ['one', 'two']} + } + render() { return ( <div> - <Topics /> + <Topics topics={this.state.topics} /> <Messages /> <hr /> <Input /> </div> ) } }
-
Fetch and display topics with a RESTful API request.
class App extends React.Component { constructor(props) { super(props) - this.state = {topics: ['one', 'two']} + this.state = {topics: []} } + componentWillMount() { + fetch('https://dreadful-spider-42903.herokuapp.com/topics') + .then(response => response.json()) + .then(json => this.setState({topics: json.data})) + } + render() { return ( <div> <Topics topics={this.state.topics} /> <Messages /> <hr /> <Input /> </div> ) } }
-
Make the
Messages
component display messages dynamically by injecting data as a property.-let Messages = () => +let Messages = ({messages}) => <div> <h4>Here's what people are saying...</h4> <ul className="list-group"> - <li className="list-group-item">Baseball is great!</li> - <li className="list-group-item">Debt sux.</li> + {messages.map(message => <li className="list-group-item">{message}</li>)} </ul> </div> // ... class App extends React.Component { constructor(props) { super(props) - this.state = {topics: []} + this.state = {messages: ['first', 'second'], topics: []} } render() { return ( <div> <Topics topics={this.state.topics} /> - <Messages /> + <Messages messages={this.state.messages} /> <hr /> <Input /> </div> ) } }
-
Click on topic to set chat topic in app.
-let Topics = ({topics}) => +let Topics = ({topics, setTopic}) => <div> <h4>Click on a topic...</h4> <ul> - {topics.map(topic => <li><a href="#">{topic}</a></li>)} + {topics.map(topic => <li><a href="#" onClick={() => setTopic(topic)}>{topic}</a></li>)} </ul> </div> // ... class App extends React.Component { constructor(props) { super(props) - this.state = {messages: ['first', 'second'], topics: []} + this.state = {messages: [], topics: []} } componentWillMount() { fetch('https://dreadful-spider-42903.herokuapp.com/topics') .then(resp => resp.json()) .then(json => this.setState({topics: json.data})) } + setTopic(topic) { + this.receiveMessage(`Joining ${topic}...`) + } + + receiveMessage(message) { + this.setState( + ({messages}) => ({messages: messages.concat(message)}) + ) + } + render() { return ( <div> - <Topics topics={this.state.topics} /> + <Topics topics={this.state.topics} setTopic={(topic) => this.setTopic(topic)} /> <Messages messages={this.state.messages} /> <hr /> <Input /> </div> ) } }
-
Actually connect to chat topic.
class App extends React.Component { constructor(props) { super(props) this.state = {messages: [], topics: []} + this.socket = new Phoenix.Socket('wss://dreadful-spider-42903.herokuapp.com/socket') + this.socket.connect() } componentWillMount() { fetch('https://dreadful-spider-42903.herokuapp.com/topics') .then(resp => resp.json()) .then(json => this.setState({topics: json.data})) } setTopic(topic) { + if (this.channel) { + this.channel.leave() + } + + this.channel = this.socket.channel(`chat:${topic}`) + this.channel.join() + this.channel.on('shout', ({data}) => this.receiveMessage(data)) this.receiveMessage(`Joining ${topic}...`) } receiveMessage(message) { this.setState( ({messages}) => ({messages: messages.concat(message)}) ) } render() { return ( <div> <Topics topics={this.state.topics} setTopic={(topic) => this.setTopic(topic)} /> <Messages messages={this.state.messages} /> <hr /> <Input /> </div> ) } }
-
Submit message to chat on topic.
-let Input = () => - <form> +let Input = ({sendMessage}) => + <form onSubmit={(event) => { + let form = event.target + sendMessage(form.elements.message.value) + form.reset() + event.preventDefault() + }}> <input name="message" className="form-control" placeholder="Say something interesting (and not gross)..." /> </form> // ... class App extends React.Component { constructor(props) { super(props) this.state = {messages: [], topics: []} this.socket = new Phoenix.Socket('wss://dreadful-spider-42903.herokuapp.com/socket') this.socket.connect() } componentWillMount() { fetch('https://dreadful-spider-42903.herokuapp.com/topics') .then(resp => resp.json()) .then(json => this.setState({topics: json.data})) } setTopic(topic) { if (this.channel) { this.channel.leave() } this.channel = this.socket.channel(`chat:${topic}`) this.channel.join() this.channel.on('shout', ({data}) => this.receiveMessage(data)) this.receiveMessage(`Joining ${topic}...`) } receiveMessage(message) { this.setState( ({messages}) => ({messages: messages.concat(message)}) ) } + sendMessage(message) { + this.channel.push('shout', {data: message}) + } + render() { return ( <div> <Topics topics={this.state.topics} setTopic={(topic) => this.setTopic(topic)} /> <Messages messages={this.state.messages} /> <hr /> - <Input /> + <Input sendMessage={(message) => this.sendMessage(message)} /> </div> ) } }
THAT'S ALL! Great job 💪