Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React set scroll position before component mount

I have the below react component which is essentially a chat-box

 render(){
    const messages = this.props.messages;
    return(
      <div id="project_chat">
        <h1>{this.props.project[0].project}</h1>
        <div className="chat_room">

          <div className="messages" ref="messages">
            <Waypoint onEnter={this.activateWayPoint}/>
            <ul>
              {messages.map((message) => {
                return(
                  <Message key={uuid.v4()} message={message}/>
                )
              })}
            </ul>
          </div>

          <div className="chat_message_box">
            <input type='text' onChange={this.handleChange} value={this.state.message} className="message_box" placeholder="enter message"/>
            <button className="submit_message" onClick={this.handleSubmit}>Submit</button>
          </div>

        </div>

      </div>
    )
  }

the problem i faced is the chat messages box starts at the topmost position of the container (scroll position starts at the top). I wanted the scroll position to be at the bottom like a normal chat room.

so i tried doing this:

  componentDidMount(){
    this.refs.messages.scrollTop = this.refs.messages.scrollHeight
  }

this triggers AFTER the component gets mounted i.e - the message box scroll position initially starts at the top and forces its way to the bottom on render.

this is normally fine but i'm using a library called react-waypoint which would help me paginate chat messages. this gets triggered every time i'm at the top of the container.

the unhappy consequence is that because the message box starts at the top initially on mount, the waypoint always gets triggered on mount as well.

my question is whether i can force the message component to start at the bottom position as opposed to starting the top and going to the bottom at the beginning

I tried doing this

  componentWillMount(){
    this.refs.messages.scrollTop = this.refs.messages.scrollHeight
  }

the problem is i dont have access to refs before the component mounts. is there any other way?

like image 694
Kannaj Avatar asked Jul 28 '16 13:07

Kannaj


1 Answers

What you want is to avoid firing this.activateWayPoint before you've set scrollTop.

You can do this by setting a state variable waypointReady to false initially. Set it to true in componentDidMount.

Then, you can modify this.activateWayPoint to check this.state.waypointReady, and return immediately if it is false.

// inside component
getInitialState() {
  return { waypointReady : false }
}
componentDidMount() {
  this.refs.messages.scrollTop = this.refs.messages.scrollHeight;
  this.setState({ waypointReady : true});
}
activateWayPoint() {
  if (! this.state.waypointReady) return;
  // Your code here!
  // ...
}

You will probably have to bind this inside your render function:

// ...
<Waypoint onEnter={this.activateWayPoint.bind(this)}/>
// ...

Alternately, instead of performing the check inside this.activateWayPoint, you might perform the check inside render:

// ...
<Waypoint onEnter={
   this.state.waypointReady ?
   this.activateWayPoint :
   null
   }/>
// ...

This assumes that your component re-renders every time you setState.

like image 200
A. Vidor Avatar answered Sep 19 '22 19:09

A. Vidor