Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to handle focus using declarative/functional style libraries like Redux and ReactJS?

In looking around to see what ways other developers are handling input focus when working with Redux I've come across some general guidance for ReactJS components such as this. My concern however is that the focus() function is imperative and I could see strange behaviours possible where multiple components are fighting over focus. Is there a redux way of dealing with focus? Is anybody dealing with pragmatically setting focus using redux and react and if so what techniques do you use?

Related:

  • How to set focus on an element in Elm?
  • Automatically focus input element after creation in purescript-halogen
  • https://github.com/cyclejs/cycle-core/issues/153
like image 272
jpierson Avatar asked Jan 17 '16 18:01

jpierson


People also ask

How do you handle focus in React?

To focus input when another element is clicked in React: Set the onClick prop on the other element. When the other element is clicked, focus the input, e.g. ref. current. focus() .

What is one reason you might not want to use Redux in your project?

There is also less setup time compared to using Redux, but all that doesn't make it better than Redux. As mentioned above, it's not best suited for large applications which need complex logic. But in some apps, Redux is just plain overkill where Context API is more suited.

How do you check if input is focused React?

To check if an element is focused in React: Set the ref prop on the element. After the element is rendered, check if the element is the active element in the document. If it is, the element is focused.


1 Answers

My approach is using ref callback, which is kind of an onRenderComplete of an element. In that callback I can focus (conditionally, if needed) and gain a reference for future focusing.

If the input is rendered conditionally after an action runs, that ref callback should fire a focus, because the ref doesn't exist yet immediately after calling the action, but only after render is done. Dealing with componentDidUpdate for things like focus just seems like a mess.

// Composer.jsx -- contains an input that will need to be focused somewhere else

class Composer extends Component {
  render() {
    return <input type="text" ref="input" />
  }

  // exposed as a public method
  focus() {
    this.refs.input.focus()
  }
}

// App.jsx

@connect(
  state => ({ isComposing: state.isComposing }),
  ...
)
class App extends Component {
  render() {
    const { isComposing } = this.props // or props, doesn't matter
    return (
      <div>
        <button onClick={::this._onCompose}>Compose</button>
        {isComposing ? <Composer ref={c => {
          this._composer = c
          this._composer && this._composer.focus() // issue initial focus
        }} /> : null}
      </div>
    )
  }

  _onCompose() {
    this.props.startComposing() // fire an action that changes state.isComposing

    // the first time the action dispatches, this._composer is still null, so the ref takes care of the focus. After the render, the ref remains so it can be accessed:

    this._composer && this._composer.focus() // focus if ref already exists
  }
}

Why not autoFocus or isFocued prop?

As HTMLInputElement has value as a prop, but focus() as a method -- and not isFocused prop -- I would keep using methods to handle that. isFocused can get a value but if the user blurs from the input, what happens to that value? It'll be out of sync. Also, as mentioned in the comments, autoFocus can conflict with multiple components

So how to decide between props and methods?

For most cases props will be the answer. Methods can be used only in a 'fire and forget' things, such as scrollToBottom in a chat when a new message comes in, scrollIntoView and such. These are one time behaviors that the store doesn't care about and the user can change with an interaction, so a boolean prop won't fit. For all other things, I'd go with props.

Here's a jsbin:

http://jsbin.com/waholo/edit?html,js,output

like image 119
elado Avatar answered Oct 01 '22 14:10

elado