Search code examples
reactjsfocuscontenteditableref

React Contenteditable Not Focusing with Ref


Feel like I'm going crazy -- can't seem to get past this. Upon inputting any text, we immediately lose focus. Calling focus() on the ref appears to have absolutely no effect.

UpdatePage.js

export default class UpdatePage extends Component {

  constructor(props) {
    super(props);
    const that = this;

    auth.onAuthStateChanged((user) => {
      db.collection('users/' + user.uid + '/updates')
      .onSnapshot(function (querySnapshot) {
        const updates = [];
        querySnapshot.forEach(function (doc) {
          const updateData = doc.data();
          updates.push({...updateData, doc_id: doc.id});
        });
        that.setState({
          updates: updates,
        });
      });
    });
  }

  render() {
    const todaysDate = new Date();

    return (
      <div>
        <UpdateDeck date={todaysDate} {...this.state}/>
      </div>
    );
  }
}

Update Deck

export default class UpdateDeck extends Component {
  render() {
    return <div key={this.props.date}>
      <UpdateCard key={"A"} {...this.props}/>
      <UpdateCard key={"B"} {...this.props}/>
    </div>;
  }
}

UpdateCard.js

export default class UpdateCard extends Component {
  render() {
    return <div>
      <Card>
        <ListGroup>
          {this.props.updates
            .map((update, i) => {
              return <Update key={'Update_' + update.doc_id}
                             update={update}
                             {...this.props}/>;
            })}
        </ListGroup>
      </Card>
    </div>;
  }
}

Update.js:

export default class Update extends Component {

  constructor(props) {
    super(props);
    this.myRef = React.createRef();
  }

  updateCard(doc_id, text) {
    const ref = this.myRef.current;
    db.collection(...).doc(doc_id).update(...)
      .then(function () {
        ref.focus();
      })
  }

  render() {
    return <ContentEditable
        key={this.props.update.doc_id}
        html={this.props.update.text}
        innerRef={this.myRef}
        disabled={false}
        onChange={e => this.updateCard(this.props.update.doc_id, e.target.value)}
      />
  }

}

Needless to say, the db.update() function updates this.props.update.text, but I'm wondering if this is the source of my issue since I'm not using state.

Using this ContentEditable npm library: https://www.npmjs.com/package/react-contenteditable


Solution

  • The reason that your focus is lost is because the component is getting remounted instead of re-rendered.

    Now one reason this things happens is because you add a key prop to the component that changes between re-renders. When this happens React things that the component has changed and remounts it.

    Now you add a key key={this.props.date} on the div and I assume on each change on contentEditable date prop might ahve changed causing each and every child of it to remount

    You also do not need a key prop unless you are returning elements from a loop

    you could simply write your code like

    export default class UpdateDeck extends Component {
      render() {
        return <div>
          <UpdateCard {...this.props}/>
          <UpdateCard {...this.props}/>
        </div>;
      }
    }