Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using React's 'ref' attribute with Material-UI

I'm trying to access input data using React's "ref" attribute on a TextField in Material-UI. There doesn't seem to be an easy way of doing this via the 'inputRef' or 'inputProps'.

The below sample shows the use of inputProps on line 26. Assigning the name of the TextField to the 'ref' property does not appear to produce a valid object.

With the “inputRef”, which according the Material-ui docs forces the use of a function, attempting to pass the field data in as an attribute also doesn't work. Ex: (txt => this.name = txt)

Has anyone found a solution?

class MediaForm extends Component {
  constructor (props) {
    super(props)
    this.state = {}
    this.handleSubmit = this.handleSubmit.bind(this)
  }

  handleSubmit (e) {
    const { title, colour } = this.refs
    e.preventDefault()
    window.alert(`New colour: ${title.value} ${colour.value}`)
  }

  render () {
    const { classes } = this.props
    return (
      <form className={classes.root}
        onSubmit={this.handleSubmit}>
        <div className={classes.field}>
          <TextField
            name='title'
            type='text'
            label='Title'
            placeholder='Movie title...'
            autoFocus
            inputProps={{ref: this.name}}
            required />
        </div>
        <div className={classes.field}>
          <Tooltip title='Add a colour the reflects the mood of the film'>
            <TextField
              name='colour'
              type='color'
              label='Mood'
              inputProps={{ref: this.name}}
              required />
          </Tooltip>
        </div>
        <Button
          variant='raised'
          color='primary'
          className={classes.button}>
          ADD
        </Button>
      </form>
    )
  }
}

MediaForm.propTypes = {
  classes: PropTypes.object.isRequired
}

export default withRoot(withStyles(styles)(MediaForm))
like image 240
John Lamy Avatar asked Apr 18 '18 09:04

John Lamy


People also ask

What is the purpose of React's ref attribute?

The ref attribute makes it possible to store a reference to a particular React element or component returned by the component render() configuration function. This can be valuable when you need a reference, from within a component, to some element or component contained within the render() function.

How do you make a text field mandatory in material UI?

We can use TextField component in Material UI to show input textbox. import TextField from "@material-ui/core/TextField"; When using the TextField component, we can pass the required attribute to mark the component as required.

What is material UI library in react?

Material UI is one of the popular React UI frameworks. Let us learn how to use material UI library in this chapter. Material UI can be installed using npm package. Material UI recommends roboto fonts for UI.

How do I create a custom ref In react?

Refs are created using React.createRef() and attached to React elements via the ref attribute. Refs are commonly assigned to an instance property when a component is constructed so they can be referenced throughout the component.

How does A ref work in react?

How a conversation between a child component and an element containing the ref might go down. This is a component that renders some text, an input field, and a button. The ref is created in the constructor and then attached to the input element when it renders.

How do I use React components?

Using the components is simple. Just import the component from the library and render it like any other React component. The nice thing about the components is that they all contain their own styles, so there isn't a global CSS file that you have to worry about.


1 Answers

You do not need refs for that. The submit event contains the form as the target. You can access the inputs in a form via form.elements:

handleSubmit (event) {
    const { title, colour } = event.currentTarget.elements;
    event.preventDefault();
    window.alert(`New colour: ${title.value} ${colour.value}`);
}

To the problem with your refs: What does this.name refer to? You did not declare it anywhere so it is undefined. Passing undefined to the ref prop has no effect. Also how should it be possible to have two input refs being bound to the same instance property name. Are you aware that the this in your render function refers to the instance of your MediaForm component and therefore this.name is a property name on your component instance (which is undefined)?

If you want to obtain the individual refs for each input you should use the callback pattern. Note that String refs are deprecated and should not be used:

render() {
    return(
        <TextField
            name='title'
            type='text'
            label='Title'
            placeholder='Movie title...'
            autoFocus
            inputProps={{ref: input => this.titleInput = input}}
            required 
        />
    );
}

EDIT:

What you probably want is known as controlled component. In this pattern your parent component keeps track of the values of it's children (often inputs):

class MediaForm extends Component {
    constructor(props) {
        super(props);
        this.state = {
            title: '',
            colour: '',
        };
    }

    handleChange = event => {
        const {name, value} = event.currentTarget;
        this.setState({[name]: value});
    };

    handleSubmit = event => {
        event.preventDefault();
        const {title, colour} = this.state;
        window.alert(`New colour: ${title} ${colour}`);
    };

    render() {
        const {classes} = this.props;
        const {title, colour} = this.state;

        return (
            <form className={classes.root} onSubmit={this.handleSubmit}>
                <div className={classes.field}>
                    <TextField
                        name="title"
                        type="text"
                        value={title}
                        onChange={this.handleChange}
                        label="Title"
                        placeholder="Movie title..."
                        required
                    />
                </div>
                <div className={classes.field}>
                    <Tooltip title="Add a colour the reflects the mood of the film">
                        <TextField
                            name="colour"
                            type="color"
                            value={colour}
                            onChange={this.handleChange}
                            label="Mood"
                            required
                        />
                    </Tooltip>
                </div>
                <Button
                    type="submit"
                    variant="raised"
                    color="primary"
                    className={classes.button}
                >
                    ADD
                </Button>
            </form>
        );
    }
}

Edit kxm42q76vv

Now your parent has full control and access over the value of each input via this.state.title and this.state.colour. Also no need for any ref here.

like image 72
trixn Avatar answered Sep 17 '22 17:09

trixn