Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

defaultValue change does not re-render input

Tags:

reactjs

I have no idea why this is not working

Demo

I have the following es6 code

const {createFactory, createClass, DOM: { label, input, button }} = React;

const tester = createFactory(createClass({
  render() {
      return label({}
               ,`Name: ${this.props.name}`
               ,input({defaultValue: this.props.name})
               ,button({onClick: this.changeName}, "Change")
             )
  },
  changeName() {
    this.setProps({name: "Wilma"})
  }
}) )

React.render(tester({name: "Fred"}), document.querySelector('body'))

Clicking the button clearly changes the props, but the old defaultValue is still in the input! So what gives? What am I doing wrong? is this a bug? Is there a workaround?

like image 497
George Mauer Avatar asked Jun 11 '15 22:06

George Mauer


People also ask

Does Prop change trigger re-render?

In order for props to change, they need to be updated by the parent component. This means the parent would have to re-render, which will trigger re-render of the child component regardless of its props.

How do you're-render React component after state change?

A React component automatically re-renders whenever there is a change in state or props, it only takes a simple state update from anywhere in the code to automatically re-render UI elements. However, you may see cases where rendering depends on other data.

Does React re-render if state changes?

React components automatically re-render whenever there is a change in their state or props. A simple update of the state, from anywhere in the code, causes all the User Interface (UI) elements to be re-rendered automatically.


2 Answers

I found what seems to be a pretty good solution to this: Use the key prop to force rendering of an entirely new input.

In my particular case, I don't need the input to be controlled with its own onChange prop, as the form surrounding it ultimately controls the state within some store which populates the defaultValue. But the store's state might be asynchronously initialized/updated, and in which case the defaultValue should be updated. So here is a condensed version of my particular case:

import React, { PropTypes } from 'react';
import { Form } from 'provide-page';

const GatherContact = ({
  classes,
  onSubmit,
  movingContactName,
  movingContactEmail,
  movingContactPhone,
  userName,
  userEmail,
  userPhone
}) => (
  <Form onSubmit={onSubmit}>
    <div className={classes.GatherContact}>
      <h2 className={classes.GatherHeading}>
        How can we contact you?
      </h2>

      <input
        type="text"
        className={classes.GatherContactInput}
        placeholder="Name"
        name="movingContactName"
        key={`movingContactName:${movingContactName || userName}`}
        defaultValue={movingContactName || userName}
        required={true}
      />

      <input
        type="email"
        className={classes.GatherContactInput}
        placeholder="Email"
        name="movingContactEmail"
        key={`movingContactEmail:${movingContactEmail || userEmail}`}
        defaultValue={movingContactEmail || userEmail}
        required={true}
      />

      <input
        type="tel"
        className={classes.GatherContactInput}
        placeholder="Phone"
        name="movingContactPhone"
        key={`movingContactPhone:${movingContactPhone || userPhone}`}
        defaultValue={movingContactPhone || userPhone}
        required={true}
      />

      {userName
        ? undefined
        : (
          <input
            type="password"
            className={classes.GatherContactInput}
            placeholder="Password"
            name="userPassword"
            required={true}
            autoComplete="new-password"
          />
        )
      }
    </div>
  </Form>
);

GatherContact.propTypes = {
  classes: PropTypes.object.isRequired,
  onSubmit: PropTypes.func.isRequired,
  movingContactName: PropTypes.string.isRequired,
  movingContactEmail: PropTypes.string.isRequired,
  movingContactPhone: PropTypes.string.isRequired,
  userName: PropTypes.string.isRequired,
  userEmail: PropTypes.string.isRequired,
  userPhone: PropTypes.string.isRequired
};

export default GatherContact;
like image 111
timbur Avatar answered Oct 10 '22 09:10

timbur


You only specify its default value, but don't tell it to change its value with a change to props.

,input({value: this.props.name})

Will change the value when this.props.name changes.

http://output.jsbin.com/melitecimo

like image 21
Michael Parker Avatar answered Oct 10 '22 09:10

Michael Parker