question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

"ref" callback and "componentDidMount" not being triggered on initial render

See original GitHub issue

Description

ref callback and componentDidMount life-cycle hook is not being triggered until after manually triggering an additional re-render with setState.

Also asked on SO, but not getting any responses: http://stackoverflow.com/questions/43009993/react-native-initial-lifecycle-hooks-not-being-called/43010267#43010267

Reproduction Steps and Sample Code

“constructor”, “componentWillMount”, and “render” are called immediately upon launching the application, as expected. However, “ref”, and “componentDidMount” are not called until manually triggering a re-render via this.setState() after the 5 second delay.

import React, { Component } from 'react';
import {
  AppRegistry,
  StyleSheet,
  Text,
  View
} from 'react-native';

class TestText extends Component {

    constructor(props, context) {
        super(props, context);
        console.warn('constructor');
        this.textRef = null;
    }

    componentWillMount() {
        console.warn('willMount');
    }

    componentDidMount() {
        console.warn('didMount');
    }

    render() {
        console.warn('render');
        return (
            <View>
                <Text
                    ref={(me) => {
                        console.warn('ref: ' + (me ? 'not null' : 'null'));
                        this.textRef = me;
                    }}>
                    {'TEST'}
                </Text>
            </View>
        );
    }

}

export default class AwesomeProject extends Component {

  constructor(props, context) {
      super(props, context);
      this.state = {
        test: 0
      };
      setTimeout(() => {
        this.setState({
            test: 1
        });
      }, 5000)
  }

  render() {
    return (
      <View style={styles.container}>
        <TestText />
      </View>
    );
  }

}

const styles = StyleSheet.create({
  container: {
    flex: 1
  }
});

AppRegistry.registerComponent('AwesomeProject', () => AwesomeProject);

Solution

Expected behavior: Shouldn’t “ref” and “componentDidMount” be called immediately after rendering. I shouldn’t have to setState to get those hooks to run.

Additional Information

  • React Native version: 0.42.3
  • Platform: Android (maybe iOS as well)
  • Development Operating System: Windows
  • Dev tools: compileSdkVersion = 23, buildToolsVersion = 23.0.1

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Reactions:16
  • Comments:7 (1 by maintainers)

github_iconTop GitHub Comments

3reactions
gauravdhimancommented, Sep 21, 2017

@sourcesoft Yes, found the solution. I am using Native Base and in my case the culprit was floatingLabel on <Item floatingLabel last> component. If I remove floatingLabel, ref works fine, but with floatingLabel I need to use getRef as explained here.

Here is the code that is working for me. Note the getRef in second input field.

<Item floatingLabel last>
    <Label>Address</Label>
    <Input
    onFocus={() => {
        // move to next field so that user an not modify this field manually
        this._detailsField._root.focus();
        // show screen to select an address
        navigate('SearchAddressScreen', {
        onSelectAddress: address => this.saveAddress(address)
        });
    }}
    value={this.state.address.text}
    />
</Item>
<Item floatingLabel last>
    <Label>Details</Label>
    <Input
    getRef={e => (this._detailsField = e)}
    multiline={true}
    numberOfLines={10}
    style={{ height: 200, textAlignVertical: 'top' }}
    onChangeText={text => this.setState({ details: text })}
    />
</Item>
3reactions
gauravdhimancommented, Sep 17, 2017

Even I am facing this issue.

Here is the test code:

import React, { Component } from 'react';
import {
  Button,
  Container,
  Content,
  Form,
  Item,
  Input,
  Label,
  Text
} from 'native-base';

export default class TestComponent extends Component {
  constructor(props) {
    super(props);
    this.refs = {};
  }

  componentDidMount() {
    console.log('=====>>>>>> 2. In componentDidMount() ....');
    this.refs.detailsField.focus();
  }

  render() {
    const { navigate } = this.props.navigation;
    return (
      <Container>
        <Content>
          <Form>
            <Item floatingLabel last>
              <Label>Details</Label>
              <Input
                ref={c => {
                  this.refs.detailsField = c;
                  console.log('=====>>>>>> 1 ....');
                  console.log(this.refs.detailsField);
                }}
                multiline={true}
                numberOfLines={10}
                style={{ height: 200, textAlignVertical: 'top' }}
                onChangeText={text => this.setState({ details: text })}
              />
            </Item>
          </Form>
        </Content>
      </Container>
    );
  }
}

ref callback is not getting called on rendering of Inpput component. Ideally we should see below console logs

=====>>>>>> 1 ....
=====>>>>>> 2. In componentDidMount() ....

But on console I am only seeing

=====>>>>>> 2. In componentDidMount() ....

Also seeing below warning / error message from React-Native (as I am calling this.refs.detailsField.focus() in componentDidMount()

Possible Unhandled Promise Rejection (id: 0):
TypeError: undefined is not an object (evaluating 'this.refs.detailsField.focus')
...
....

Looks like ref callback on Input field is not getting called at all. Is my understanding wrong about ref or is it a bug ?

Please try this test case.

Read more comments on GitHub >

github_iconTop Results From Across the Web

componentDidMount called BEFORE ref callback
React will only call ref callbacks for elements that you actually returned from render. ... and initially this.state.isLoading is true , you ...
Read more >
Refs and the DOM - React
React will call the ref callback with the DOM element when the component mounts, and call it with null when it unmounts. Refs...
Read more >
React Callback Refs — a Complex Case | by E.Y. - Medium
This is because ref is first set after the first render() , but before componentDidMount() . So when you first render, there's no...
Read more >
Rendering and Updating Data using Component Lifecycle ...
The componentDidMount() method will be triggered as soon as the component is mounted or inserted into the DOM. The basic syntax to use ......
Read more >
React Lifecycle - W3Schools
The componentDidMount() method is called after the component is rendered. This is where you run statements that requires that the component is already...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found