yyc
yyc

Reputation: 298

React ref state is null

I want to access the state of a Child component by using refs, but the state of the ref is always null.

In my React app, I have an Editor(basically, it is a form) that manipulates its own states, e.g. value change, update. The editor is used on multiple pages.

Editor.jsx

    export default class Editor extends React.Component {
        constructor(props) {
            super(props);
            this.state = {
                value1: null,
                ... other values 
            };
         }

         onValue1Change = (e) => {
            this.setState({value1: e.target.value});
         }

         onSave = (e) => {
            // save values
         }

         render() {
             return (
                <div>
                    <input value={this.state.value1} onChange={this.onValue1Change}/>
                    ... other input fields
                    <button onClick={this.onSave}>Save</button>
                </div>
             )
         }
     }

Now, there is a RegisterForm which covers all fields in the Editor. I made a small change in the Editor to hide the Save button so I can use it in the RegisterForm:

RegisterForm.jsx

    export default class RegisterForm extends React.Component {
        constructor(props) {
            super(props);
            this.state = {
                email: null,
                firstname: null,
                lastname: null
            };
            this.Editor = React.createRef();
        }

        onSave = (e) => {
            let childState = this.Editor.current.state;
            // childState is ALWAYS null!
        }

        render() {
            return (
                <div>
                    <input value={this.state.email} onChange={this.onEmailChange}/>
                    <input value={this.state.firstname} onChange={this.onFirstnameChange}/>
                    <input value={this.state.lastname} onChange={this.onLastnameChange}/>
                    ...
                    <Editor ref={this.Editor} showSave={false}/>
                    ...
                    <button onClick={this.onSave}>Save</button>
                </div>
            )
        }
    }

Turns out this.Editor.current.state is always null.

I have two questions.

  1. Why this.Editor.current.state is null?

  2. If I want to use props, how should I change my code? E.g. If I let RegisterForm pass props to Editor, I'd imagine something like this:

Editor.jsx

    export default class Editor extends React.Component {
         // same constructor
         onValue1Change = (e) => {
            this.setState({value1: e.target.value}, () => {
                if(this.props.onValue1Change) this.props.onValue1Change(e);
            });
         }
         // same render
     }

RegisterForm.jsx

     export default class RegisterForm extends React.Component {
        constructor(props) {
            super(props);
            this.state = {
                email: null,
                firstname: null,
                lastname: null,
                value1: null,
            };
        }

        onValue1Change = (e) => {
            this.setState({value1: e.target.value});
        }

        render() {
            return (
                <div>
                    <Editor showSave={false} onValue1Change={this.onValue1Change}/>
                    ...
                </div>
            )
        }
    }

does it make the Child component render twice? Any suggestions on how to improve it?

Upvotes: 1

Views: 2589

Answers (1)

Al Duncanson
Al Duncanson

Reputation: 804

You are passing the ref as a prop to the <Editor/> component but not doing anything with it after that.

For example:

const FancyButton = React.forwardRef((props, ref) => (
  <button ref={ref} className="FancyButton">
    {props.children}
  </button>
));

// You can now get a ref directly to the DOM button:
const ref = React.createRef();
<FancyButton ref={ref}>Click me!</FancyButton>;

Receive props and ref through the forwardRef() callback parameter, then pass the ref to the child node.

This is called ref forwarding

I made a code sandbox for you to test it!

Upvotes: 1

Related Questions