user3162553 user3162553 - 1 month ago 17
React JSX Question

Passing variables to React components gives "unknown property errror"

Super simple or so I thought! Just trying to pass a string to another component but it doesn't recognize the property because it is using string interpolation.

edit

I believe it could be related to upgrading redux-form which changed the input selector. I'm using React 15.3.1 and I believe they changed how inputs worked which affected Redux. (https://github.com/erikras/redux-form/issues/1249).

import React, { Component } from 'react';
import { connect } from 'react-redux';
import * as actions from '../../actions';
import { reduxForm } from 'redux-form';

import errorListItem from '../error-list-item/index.js';

class Signup extends Component {
handleFormSubmit(formProps) {
this.props.signupUser(formProps);
}

renderAlert() {
const errorObject = this.props.errorMessage;

// single (connection/api) error
if (errorObject === 'Network Error') {
return (
<div className="alert alert-danger">
<errorListItem message="hello" />
</div>
);

// error object from BE
} else if (errorObject && typeof errorObject === 'object') {
const keys = Object.keys(errorObject);

debugger;
if (keys.length === 0) return;

return Object.keys(errorObject).map(field => {
return errorObject[field].map(problem => {
const message = `${field} ${field}`;

return (
<ul className="error-message-list">
<errorListItem message={message} />
</ul>
);
});
});
}
}

render() {
const { handleSubmit, fields: { email, password, passwordConfirm, username }} = this.props;

return (
<div className="signup">
<form onSubmit={handleSubmit(this.handleFormSubmit.bind(this))}>
<fieldset className="form-group">
<label>Username:</label>
<input className="form-control" {...username} />
{username.touched && username.error && <div className="error">{username.error}</div>}
</fieldset>
<fieldset className="form-group">
<label>Email:</label>
<input className="form-control" {...email} />
{email.touched && email.error && <div className="error">{email.error}</div>}
</fieldset>
<fieldset className="form-group">
<label>Password:</label>
<input type="password" className="form-control" {...password} />
{password.touched && password.error && <div className="error">{password.error}</div>}
</fieldset>
<fieldset className="form-group">
<label>Confirm Password:</label>
<input className="form-control" {...passwordConfirm} />
{passwordConfirm.touched && passwordConfirm.error && <div className="error">{passwordConfirm.error}</div>}
</fieldset>
<button action="submit" className="btn btn-primary">Sign up</button>
</form>
{this.renderAlert()}
</div>
);
}
}

function validate(formProps) {
const errors = {};

if (!formProps.email) {
errors.email = 'Please enter an email';
}

if (!formProps.password) {
errors.password = 'Please enter a password';
}

if (!formProps.passwordConfirm) {
errors.passwordConfirm = 'Please enter a password confirmation';
}

if (!formProps.username) {
errors.username = 'Please enter a username';
}

// Passwords match
if (formProps.password !== formProps.passwordConfirm) {
errors.password = 'Passwords must match';
}

return errors;
}

function mapStateToProps(state) {
return { errorMessage: state.auth.errors };
}

export default reduxForm({
form: 'signup',
fields: ['email', 'password', 'passwordConfirm', 'username'],
validate
}, mapStateToProps, actions)(Signup);


Child component:

import React from 'react';

require('./styles.scss');

const errorListItem = ({ message }) => {
return (<li>{message}</li>)
}

export default errorListItem;


Attempted Solutions:


  1. Passing the property without using a variable

    <ul className="error-message-list">
    <errorListItem message={`${field} ${problem}`} />
    </ul>

  2. Passing the property using ES6 destructuring

    <ul className="error-message-list">
    <errorListItem message />
    </ul>

  3. Passing the property using older JS syntax without ``.

    const message = "" + field + " " + problem + "";

    return (
    <ul className="error-message-list">
    <errorListItem message={message} />
    </ul>
    );

  4. Try to make the child component render anything!

    const errorListItem = ({ message }) => {
    return <li>Help Me, Obi-Wan Kenobi. You're My Only Hope</li>
    }



Documentation consulted:

https://facebook.github.io/react/warnings/unknown-prop.html

Error Message:

Warning: Unknown prop `message` on <errorListItem> tag. Remove this prop from the element.


Expected Behavior:


  1. It should be able to pass a string as a property. If I use the below, it will work:

    <ul className="error-message-list">
    <errorListItem message='message' />
    </ul>

  2. If it doesn't render, the error message should not be "unknown property" but instead invalid property value given.



Versions:

"react": "^0.14.3",
"react-redux": "^4.0.0",
"react-router": "^2.0.1",
"redux": "^3.0.4",
"redux-form": "^5.3.1",

Answer

I believe the problem is in how you've named your errorListItem component. In JSX, custom component names should start with an uppercase letter, while normal html ones in lowercase. So React thinks you're trying to render a "normal" tag called errorListItem with an unknown property. The error shows up because React validates the props passed to html tags: https://facebook.github.io/react/warnings/unknown-prop.html

Try to rename your stateless component when you import it (and to be consistent also when you define it) in this way:

import ErrorListItem from '../error-list-item/index.js';
// Rest of your code...
<ErrorListItem message={message} />