0

experts!

I make web service using react.

I want to make page to modify user info.

I can receive user data and set data to input's value.

But, react occur warning it.

Warning: A component is changing an uncontrolled input of type text to be controlled. ~~

I think. I did something wrong. when componentDidMount().

I want to know, how to initialize form data using async data.

Sorry about my poor english skill.

This code is part of my code.

export class UpdatedUser {
  @observable private _name: string;
  @observable private _phone: string;
  @observable private _email: string;
  
  // skip setters, getters.
}

interface MyPageComponentProps extends RouteComponentProps<{}> {
  global?: GlobalService;
}

interface MyPageComponentState {
  user: UpdatedUser;
}

@inject('global')
@observer
class MyPageComponent extends React.Component<MyPageComponentProps, MyPageComponentState> {
  constructor(props: MyPageComponentProps) {
    super(props);
    this.state = {
      user: new UpdatedUser(),
    };
  }

  componentDidMount() {
    if (this.props.global) {
      userService.getUser(this.props.global.loginedInfo.idx + '').subscribe((res: any) => {
        if (res.result === 'success') {
          this.setState((prev: MyPageComponentState) => ({
            user: update(prev.user, {$set: {
              name: res.memberInfo.name,
              phone: res.memberInfo.phone,
              email: res.memberInfo.email,
            } as UpdatedUser})
          }));
        } else {
          alert(res.msg);
        }
      });
    }
  }

  render() {
    return (
      <form className="user-info" onSubmit={this.updateUser}>
        <h3 className="title">Modify User Info</h3>
        <div className="form-group">
          <label htmlFor="name" className="form-label">name</label>
          <input type="text" id="name" className="form-control" value={this.state.user.name} onChange={this.onChangeInfo} />
        </div>
        <div className="form-group">
          <label htmlFor="phone" className="form-label">phone</label>
          <input type="text" id="phone" className="form-control" value={this.state.user.phone} onChange={this.onChangeInfo} />
        </div>
        <div className="form-group">
          <label htmlFor="email" className="form-label">email</label>
          <input type="text" id="email" className="form-control" value={this.state.user.email} onChange={this.onChangeInfo} />
        </div>
        <div className="btn-group">
          <button type="submit" className="btn raised primary">수정</button>
          <button className="btn raised secondary" onClick={() => this.props.history.goBack()}>취소</button>
        </div>
      </form>
    );
  }

export default MyPageComponent;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
Jong-Hyen Kim
  • 525
  • 2
  • 4
  • 15

1 Answers1

0

The warning you get is about controlled and uncontrolled components. Basically, you can work with elements such as input, textarea and select having the state in the internal state of a React component or keeping it in the DOM.

In your code, you are keeping the UpdatedUser info in the local state and propagating its data with value and onChange, so you are controlling the inputs. However, where is your onChange callback? It does not exist. Try adding that method to your class and it should work. Take a look at the documentation about controlled components

The alternative approach is having uncontrolled inputs, in which case, you need to pass a defaultValue prop to your inputs instead of value and onChange, like this:

    <input
      defaultValue="Bob"
      type="text"
      ref={(input) => this.input = input}
    />

If the updateUser method gets triggered, you can simply get the new values from your ref elements:

updateUser(event) {
    event.preventDefault()
    console.log('New value: ' + this.input.value)
    this.props.onSubmit(this.input.value)
}
albertoblaz
  • 550
  • 5
  • 19