Nick bo
Nick bo

Reputation: 35

How to render a form with Users information ( React + Redux )

I've managed to get the users information using axios request. I've also managed to render users info on a view using a component that i created. My problem is that i cant display it on an another component i have created which is called ProfileForm. ProfileForm is used as form for updating the info of the user. I want to set the state on the constractor with the user info.

Also, when i change the values to this.props.user.username etc.. i receive two errors:

Warning: Failed prop type: The prop value is marked as required in TextFieldGroup, but its value is undefined. in TextFieldGroup (at ProfileForm.js:112) in ProfileForm (at ProfilePage.js:23)

and the second is

warning.js:36 Warning: TextFieldGroup is changing an uncontrolled input of type text to be controlled. Input elements should not switch from uncontrolled to controlled (or vice versa). Decide between using a controlled or uncontrolled input element for the lifetime of the component.

class ProfileForm extends React.Component
  constructor(props) {
      super(props);
      this.state = {
        username: '',
        email: '',
        password: '',
        passwordConfirmation: '',
        errors: {},
        isLoading: false,
        invalid: false
      };

      this.handleChange = this.handleChange.bind(this);
      this.handleSubmit = this.handleSubmit.bind(this);
    }

    handleChange(event) {
      this.setState({ [event.target.name]: event.target.value });
    }

    render() {
      const { errors } = this.state;
      return (
        <form onSubmit={this.handleSubmit}>

          <TextFieldGroup
            error={errors.username}
            placeholder="Username"
            onChange={this.handleChange}
            value={user.username} <-- Here should be the bind
            field="username"
          />
          <TextFieldGroup
            error={errors.email}
            placeholder="Email"
            onChange={this.handleChange}
            checkUserExists={this.checkUserExists}
            value={user.email} <-- Here should be the bind
            field="email"
          />
          <TextFieldGroup
            error={errors.password}
            placeholder="Password"
            onChange={this.handleChange}
            value={user.password} <-- Here should be the bind
            field="password"
          />
          <div className="form-group">
                <button disabled={this.state.isLoading || this.state.invalid} className="btn btn-primary btn-md btn-block">Update</button>
          </div>
        </form>
    );
  }
}

export default ProfileForm;

Here is my ProfilePage

class ProfilePage extends React.Component { 
        componentDidMount() {
          this.props.getUser();
        }

        render() {
          const { profileUpdateRequest, addFlashMessage, getUser, isUserExists } = this.props;
          return (
            <div className="row">
                  <div className="row text-center">
                    <UserProfile user={this.props.user} /> <-- This works!!!!
                  </div>
                  <ProfileForm
                      profileUpdateRequest={profileUpdateRequest}
                      addFlashMessage={addFlashMessage}
                      getUser={getUser}
                      user={this.props.user} <--- This doesnt work!!!!
                      isUserExists={isUserExists}
                   />                      
            </div>
        );
      }
    }

and my UserProfile which works

export default function UserProfile({ user }) {

  const userProfile = (
    <div className="row">
      {user.username} {user.email}
    </div>
  );

  return (
    <div>
      {userProfile}
    </div>
  );
}

My ProfileUpdateAction action

export function getUser() {
  return dispatch => {
    return axios.get('/api/user')
    .then(res => res.data)
    .then(data => dispatch(setUser(data.user)));
  }
}

And my reducer

import { SET_USER } from '../actions/profileUpdateActions';

export default function user(state = [], action = {}) {
  switch(action.type) { 
    case SET_USER:
      return action.user;
    default: return state;
  }
}

My textFieldGroup

const TextFieldGroup = ({ field, value, label, error, type, onChange, placeholder, min, checkUserExists, disabled }) => {
      return (
        <div className={classnames("form-group", {'has-error': error})}>
              <label className="control-label">{label}</label>
              <input
                type={type}
                name={field}
                className="form-control"
                value={value}
                min={min}
                onChange={onChange}
                onBlur={checkUserExists}
                placeholder={placeholder}
                disabled={disabled}
              />
              {error && <span className="help-block">{error}</span>}
        </div>
      );
    }

    TextFieldGroup.propTypes = {
      field: React.PropTypes.string.isRequired,
      value: React.PropTypes.string.isRequired,
      label: React.PropTypes.string,
      error: React.PropTypes.string,
      min: React.PropTypes.string,
      disabled: React.PropTypes.bool,
      placeholder: React.PropTypes.string.isRequired,
      type: React.PropTypes.string.isRequired,
      onChange: React.PropTypes.func.isRequired,
      checkUserExists: React.PropTypes.func
    }
    TextFieldGroup.defaultProps = {
      type: 'text'
    }
    export default TextFieldGroup;

Upvotes: 0

Views: 370

Answers (1)

Eric N
Eric N

Reputation: 2206

In UserProfile, you're using a stateless component that is passed in props as an argument. In the function params, you destructure user to be its own constant. Thats cool and works well.

However, in UserForm, you have a class-based component. The props object is attached to the object's context (this). So to access it, you need to use this.props.user.

Upvotes: 1

Related Questions