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.

Changing defaultValue doesn't re-render input, causes hidden state in the db

See original GitHub issue

I posted this on StackOverflow but the dearth of answers makes me think it might be a bug.

Given the following simple 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 doesn’t re-render the input and it still says “Fred” even though this.props.name is “Wilma”.

Demo

Issue Analytics

  • State:closed
  • Created 8 years ago
  • Comments:8

github_iconTop GitHub Comments

192reactions
ghostcommented, Aug 31, 2016

I posted this on the SO but I’ll include it here as well.

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;
67reactions
sophiebitscommented, Jun 11, 2015

The answer you got on Stack Overflow is correct. defaultValue only specifies the value when the input is initially created; if you want it to remain updated you need to use value and handle onChange events correctly.

We don’t update when defaultValue changes because otherwise you have two sources (the user’s input and your component props) trying to control the value, and it wouldn’t be clear what should happen when they conflict. Instead, we force you to think about and write out the actual behavior you want.

Read more comments on GitHub >

github_iconTop Results From Across the Web

defaultValue change does not re-render input - Stack Overflow
I found what seems to be a pretty good solution to this: Use the key prop to force rendering of an entirely new...
Read more >
Re-render DefaultValue when Value Changes in React
React will never update the input tag if the value passed to defaultValue changes. It was meant to be a default/starting value only,...
Read more >
How to Save State to LocalStorage & Persist on Refresh with ...
We'll set that preference in localStorage and read that value so that any time they ... Step 1: Using React state to hide...
Read more >
React Gotchas, Anti-Patterns, and Best Practices | by Steven Li
A potential anti-pattern is calling setState in this method as it would cause an additional re-render. If you find yourself setting the state...
Read more >
Dynamic behavior in Svelte: working with variables and props
You can also specify a default initial value for a prop. This will be used if the component's consumer doesn't specify the prop...
Read more >

github_iconTop Related Medium Post

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