I'm writing a simple "console" that shows messages in a chat-like manner. With messages appearing from the bottom, and moving up.
I have the working code, but I'd like to animate the appearing messages by scrolling the container to the bottom each time a new "li" is added.
Current code:
import React from 'react';
import { render, findDOMNode } from 'react-dom';
export default React.createClass({
componentDidUpdate : function(){
var node = findDOMNode(this);
node.scrollTop = node.scrollHeight;
},
render() {
return (
<ul id="log">
{
this.props.messages.map(function(message, index){
return <li key={index}>[{message.time.format('HH:mm:ss')}] {message.action}</li>
})
}
</ul>
)
}
})
The messages
prop comes from the parent component and the store.
I found this velocity plugin: https://github.com/twitter-fabric/velocity-react and I can't figure out how to use it in my situation. All the examples don't seem to apply (or maybe I just don't understand them).
I'm quite new to react, and some concepts still confuse me, so please be understanding.
I don't want to use jQuery.
The velocity-react plugin provides already implemented React components for using Velocity's animations.
I guess that the scroll functionality can be implemented via animations too, but Velocity library has scroll command. I've reveiwed velocity-react plugin and it provides interface (components) for the animations. There isn't any support for the Velocity commands.
It's pretty easy to use Velocity commands in React. I've created react-velocity-scroll repo based on your question and there is a live demo of sending/listing messages in a chat-like manner.
Please note that the Velocity library is included in the example via velocity-react plugin. Its recommended to include the plugin for future advanced animations, because it provides already implemented React components for using Velocity's animations. However the repo don't use any animations. It uses only Velocity library's scroll command. If you prefer - you can import Velocity library independently.
However, here are my components. Please focus on MessageItem component - once a new message is being added, then scroll down to it.
App
import React from 'react';
import MessagesList from './MessagesList';
const style = {
textAlign: 'center'
};
class App extends React.Component{
constructor(props) {
super(props);
this.state = {
/**
* @type Array - Store sent messages
*/
messages: [],
/**
* @type String - Store the input value.
* It's reset on message sent
*/
text: ''
}
}
handleOnChange(e) {
const text = e.target.value;
this.setState({ text });
}
handleOnKeyPress(e) {
const text = e.target.value;
// Send the message on `Enter` button press
if (e.key === 'Enter') {
this.sendMessage(text);
}
}
/**
* Add the message to the state and reset the value
* of the input
*
* @param String text - Message text
*/
sendMessage(text) {
const { messages } = this.state;
const message = { date: new Date(), text };
this.setState({
messages: messages.concat([message]),
text: ''
});
}
render() {
const { messages, text } = this.state;
return <div style={style}>
<h1>Please enter your text message:</h1>
<input
value={text}
placeholder="Press Enter for sending"
onChange={this.handleOnChange.bind(this)}
onKeyPress={this.handleOnKeyPress.bind(this)} />
<MessagesList messages={messages} />
</div>
}
}
export default App;
MessagesList
import React from 'react';
import MessageItem from './MessageItem';
const style = {
height: '100px',
overflowY: 'scroll'
};
const MessagesList = (props) => {
let { messages } = props;
messages = messages.map( function(message, index){
return <MessageItem key={index} index={index} message={message} />
});
return <ul style={style}>{messages}</ul>
};
export default MessagesList;
MessageItem
import React from 'react';
import ReactDOM from 'react-dom';
const Velocity = require('../node_modules/velocity-react/lib/velocity-animate-shim');
const style = {
listStyle: 'none'
};
class MessageItem extends React.Component{
componentDidMount() {
const parentNode = ReactDOM.findDOMNode(this).parentNode;
const node = ReactDOM.findDOMNode(this);
// Once a new item is being added, then scroll down to it
Velocity(node, 'scroll', {
duration: 500,
container: parentNode,
queue: false
});
}
render() {
const { message } = this.props;
return <li style={style}>{message.date + ' - ' + message.text}</li>
}
}
export default MessageItem;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With