Skip to content

Instantly share code, notes, and snippets.

@bugasmarcondes
Last active July 21, 2021 01:01
Show Gist options
  • Save bugasmarcondes/7ea899745b64c94f6758627af9026832 to your computer and use it in GitHub Desktop.
Save bugasmarcondes/7ea899745b64c94f6758627af9026832 to your computer and use it in GitHub Desktop.
React.useImperativeHandle
// useImperativeHandle: scroll to top/bottom
// http://localhost:3000/isolated/exercise/05.js
import * as React from 'react'
// @1, const
// @2, ref
const MessagesDisplay = React.forwardRef(function MessagesDisplay(
{messages},
ref,
) {
const containerRef = React.useRef()
React.useLayoutEffect(() => {
scrollToBottom()
})
// @3
// console.log('@ ref', ref)
// @4
// this is basically what useImperativeHandle does
// React.useLayoutEffect(() => {
// ref.current = {
// scrollToTop,
// scrollToBottom,
// }
// })
function scrollToTop() {
containerRef.current.scrollTop = 0
}
function scrollToBottom() {
containerRef.current.scrollTop = containerRef.current.scrollHeight
}
// @5
React.useImperativeHandle(ref, () => ({
scrollToTop,
scrollToBottom,
}))
return (
<div ref={containerRef} role="log">
{messages.map((message, index, array) => (
<div key={message.id}>
<strong>{message.author}</strong>: <span>{message.content}</span>
{array.length - 1 === index ? null : <hr />}
</div>
))}
</div>
)
})
// @1, ok but need to disable eslint
// MessagesDisplay = React.forwardRef(MessagesDisplay) // eslint-disable-line no-func-assign
function App() {
// @3
const messageDisplayRef = React.useRef('initialize')
const [messages, setMessages] = React.useState(allMessages.slice(0, 8))
const addMessage = () =>
messages.length < allMessages.length
? setMessages(allMessages.slice(0, messages.length + 1))
: null
const removeMessage = () =>
messages.length > 0
? setMessages(allMessages.slice(0, messages.length - 1))
: null
const scrollToTop = () => messageDisplayRef.current.scrollToTop()
const scrollToBottom = () => messageDisplayRef.current.scrollToBottom()
return (
<div className="messaging-app">
<div style={{display: 'flex', justifyContent: 'space-between'}}>
<button onClick={addMessage}>add message</button>
<button onClick={removeMessage}>remove message</button>
</div>
<hr />
<div>
<button onClick={scrollToTop}>scroll to top</button>
</div>
<MessagesDisplay ref={messageDisplayRef} messages={messages} />
<div>
<button onClick={scrollToBottom}>scroll to bottom</button>
</div>
</div>
)
}
export default App
const allMessages = [
`Leia: Aren't you a little short to be a stormtrooper?`,
`Luke: What? Oh... the uniform. I'm Luke Skywalker. I'm here to rescue you.`,
`Leia: You're who?`,
`Luke: I'm here to rescue you. I've got your R2 unit. I'm here with Ben Kenobi.`,
`Leia: Ben Kenobi is here! Where is he?`,
`Luke: Come on!`,
`Luke: Will you forget it? I already tried it. It's magnetically sealed!`,
`Leia: Put that thing away! You're going to get us all killed.`,
`Han: Absolutely, Your Worship. Look, I had everything under control until you led us down here. You know, it's not going to take them long to figure out what happened to us.`,
`Leia: It could be worse...`,
`Han: It's worse.`,
`Luke: There's something alive in here!`,
`Han: That's your imagination.`,
`Luke: Something just moves past my leg! Look! Did you see that?`,
`Han: What?`,
`Luke: Help!`,
`Han: Luke! Luke! Luke!`,
`Leia: Luke!`,
`Leia: Luke, Luke, grab a hold of this.`,
`Luke: Blast it, will you! My gun's jammed.`,
`Han: Where?`,
`Luke: Anywhere! Oh!!`,
`Han: Luke! Luke!`,
`Leia: Grab him!`,
`Leia: What happened?`,
`Luke: I don't know, it just let go of me and disappeared...`,
`Han: I've got a very bad feeling about this.`,
`Luke: The walls are moving!`,
`Leia: Don't just stand there. Try to brace it with something.`,
`Luke: Wait a minute!`,
`Luke: Threepio! Come in Threepio! Threepio! Where could he be?`,
].map((m, i) => ({id: i, author: m.split(': ')[0], content: m.split(': ')[1]}))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment