9

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.

Piotr Ma'niak
  • 230
  • 3
  • 13
  • so u got the react part working and u r seeking pure js scrolling? – goldylucks May 07 '16 at 15:18
  • Yes the code above is working. I'd like to animate the scroll. I know how to do this using jQuery, but attaching jQuery to react feels stupid. Meanwhile React animation plugins escape my understanding. I used "pure" velocity before, and I know how performant it is. It would be nice to be able to use it in React. So the question is virtually about velocity js, but I'm open to other suggestions. – Piotr Ma'niak May 09 '16 at 07:57
  • a more accurate title would b: "javascript scroll animation without jquery"; which would hav brought u here: http://stackoverflow.com/questions/8917921/cross-browser-javascript-not-jquery-scroll-to-top-animation – goldylucks May 09 '16 at 19:43
  • Thanks! Though vanilla JS isn't what I'm looking for. The title is "react-velocity", because I was looking for help with velocity or suggestions about other animation libraries that go nicely with react. I was focusing on velocity in particular, because of the easing functions and other tweaks it offers. I thought that experimenting with a ready set of tools would help me arrive at desired effect way faster. I initially went for vanilla & Robert Penner's easing only to find out that this would be really tedious. Plus, once fully understood velocity would be useful in the entire project. – Piotr Ma'niak May 12 '16 at 14:44
  • This animation issue is not a blocker, so I let it wait for someone who is an expert on velocityjs. Until then - there's a whole app to make ;) Once I come to the point when I need it badly I will try to figure it out again. And if I fail, I'll probably end up copying the easing functions from velocity :) Thanks for your input anyway! – Piotr Ma'niak May 12 '16 at 14:49
  • @PiotrMa'niak did you manage to check my solution/answer below? Thanks. – Jordan Enev Mar 20 '17 at 14:13
  • @JordanEnev - sory nope - my other project is killing me now and the scroll animation thing is really low priority anyway. But I really appreciate it and definitely will check it out at some point. If I do I'll let you know. Thanks! – Piotr Ma'niak Mar 29 '17 at 08:07
  • Alright :) I created a repo for you, so you can easily play with it. Good luck! – Jordan Enev Mar 29 '17 at 08:12

1 Answers1

4

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;
Jordan Enev
  • 12,130
  • 2
  • 37
  • 59