fix(bubble-input): maintain focus by handling blur events

Use forwardRef to expose the content editable element and let the parent component control the focus

fix #1 #2
This commit is contained in:
Takuya Matsuyama 2022-05-13 16:15:28 +09:00
parent 5fba2eceaa
commit 5b86470066
3 changed files with 28 additions and 19 deletions

View file

@ -1,4 +1,4 @@
import { useState, useCallback, useEffect } from 'react'
import { useState, useCallback } from 'react'
import './App.css'
import Chat from './chat'
import Bubble from './bubble'
@ -17,13 +17,6 @@ function App() {
}
}, [newMessage, messages])
useEffect(() => {
const el = document.querySelector('.bubble.input > div')
if (el) {
el.focus()
}
}, [])
return (
<div className="App">
<Chat>

View file

@ -1,8 +1,9 @@
import React, { useCallback, useState } from 'react'
import React, { useCallback, useState, useRef, useEffect } from 'react'
import './bubble-input.css'
import ContentEditable from './content-editable'
const BubbleInput = ({ onChange, onSubmit, value }) => {
const refEditable = useRef()
const [submitted, setSubmitted] = useState(false)
const handleChange = useCallback(
@ -25,7 +26,15 @@ const BubbleInput = ({ onChange, onSubmit, value }) => {
},
[onSubmit]
)
console.log('value:', value)
const handleBlur = useCallback(() => {
const { current: elDiv } = refEditable
if (elDiv) {
elDiv.focus()
}
}, [refEditable])
useEffect(() => handleBlur(), [handleBlur])
return (
<div
className={`bubble input ${value.length === 0 ? 'empty' : ''} ${
@ -33,8 +42,10 @@ const BubbleInput = ({ onChange, onSubmit, value }) => {
}`}
>
<ContentEditable
ref={refEditable}
onChange={handleChange}
onKeyDown={handleKeyDown}
onBlur={handleBlur}
value={value}
/>
</div>

View file

@ -1,17 +1,14 @@
import * as React from 'react'
class ContentEditable extends React.Component {
constructor(props) {
super(props)
this.refElement = React.createRef()
}
render() {
const { innerRef } = this.props
return (
<div
key={Math.random()}
ref={this.refElement}
ref={innerRef}
onInput={this.emitChange}
onBlur={this.emitChange}
onBlur={this.handleBlur}
onKeyDown={this.emitKeyDown}
contentEditable
spellCheck="false"
@ -21,12 +18,12 @@ class ContentEditable extends React.Component {
}
shouldComponentUpdate(nextProps) {
const { current: div } = this.refElement
const { current: div } = this.props.innerRef
return nextProps.value !== div.innerText
}
emitChange = () => {
const { current: div } = this.refElement
const { current: div } = this.props.innerRef
var value = div.innerText
if (this.props.onChange && value !== this.lastValue) {
this.props.onChange({
@ -42,6 +39,14 @@ class ContentEditable extends React.Component {
const { onKeyDown } = this.props
onKeyDown && onKeyDown(e)
}
handleBlur = e => {
this.emitKeyDown(e)
const { onBlur } = this.props
onBlur && onBlur(e)
}
}
export default ContentEditable
export default React.forwardRef((props, ref) => {
return <ContentEditable innerRef={ref} {...props} />
})