简体   繁体   中英

React child component not fetching props and updating state

I have a form that uses a child component with input fields. I have used props to get the data from the parent component, but it's not adding the prop value to the input field. There is no errors in the console.

Parent component:

const {
  address,
  errors
} = this.state;

return (
    <form noValidate autoComplete="off" onSubmit={this.onSubmit.bind(this)}>
     <LocationInputGroup
        errors={errors}
        address={address}
     />

     <Button
        type="submit"
        style={{ marginRight: 10, marginTop: 20 }}
        variant="callToAction"
    > Submit</Button>
    </form>
);

Child component:

constructor(props) {
  super(props);

  this.state = {
     address: "",
     errors: {}
  };
}

componentDidMount() {
        this.setState({
            errors: this.props.errors,
            address: this.props.address
        });
}

render() {
  const {
    address,
    errors
  } = this.state;
  return (
    <div>
      <InputGroup
        value={address}
        error={errors.address}
        label="Address"
        name={"address"}
        onChange={e => this.setState({ address: e.target.value })}
        placeholder={"Address"}
      />
    </div>
  );
}

InputGroup component:

class InputGroup extends Component {
    constructor(props) {
        super(props);
    }

    //TODO check if scrolling still changes with number inputs
    //Bug was in Chrome 73 https://www.chromestatus.com/features/6662647093133312
    //If it's no longer a bug these listeners can be removed and the component changed back to a stateless component
    handleWheel = e => e.preventDefault();

    componentDidMount() {
        if (this.props.type === "number") {
            ReactDOM.findDOMNode(this).addEventListener("wheel", this.handleWheel);
        }
    }

    componentWillUnmount() {
        if (this.props.type === "number") {
            ReactDOM.findDOMNode(this).removeEventListener("wheel", this.handleWheel);
        }
    }

    render() {
        const {
            disabled,
            classes,
            error,
            value,
            name,
            label,
            placeholder,
            type,
            isSearch,
            onChange,
            onBlur,
            onFocus,
            multiline,
            autoFocus,
            InputProps = {},
            autoComplete,
            allowNegative,
            labelProps
        } = this.props;

        if (type === "phone") {
            InputProps.inputComponent = PhoneNumberInputMask;
        }

        let onChangeEvent = onChange;
        //Stop them from entering negative numbers unless they explicitly allow them
        if (type === "number" && !allowNegative) {
            onChangeEvent = e => {
                const numberString = e.target.value;
                if (!isNaN(numberString) && Number(numberString) >= 0) {
                    onChange(e);
                }
            };
        }

        return (
            <FormControl
                className={classes.formControl}
                error
                aria-describedby={`%${name}-error-text`}
            >
                <FormatInputLabel {...labelProps}>{label}</FormatInputLabel>
                <TextField
                    error={!!error}
                    id={name}
                    type={type}
                    value={value}
                    onChange={onChangeEvent}
                    margin="normal"
                    onBlur={onBlur}
                    onFocus={onFocus}
                    InputProps={{
                        ...InputProps,
                        classes: {
                            input: classnames({
                                [classes.input]: true,
                                [classes.searchInput]: isSearch
                            })
                        }
                    }}
                    placeholder={placeholder}
                    multiline={multiline}
                    autoFocus={autoFocus}
                    disabled={disabled}
                    autoComplete={autoComplete}
                    onWheel={e => e.preventDefault()}
                />

                <FormHelperText
                    className={classes.errorHelperText}
                    id={`${name}-error-text`}
                >
                    {error}
                </FormHelperText>
            </FormControl>
        );
    }
}

InputGroup.defaultProps = {
    value: "",
    type: "text",
    labelProps: {}
};

InputGroup.propTypes = {
    error: PropTypes.string,
    value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
    name: PropTypes.string.isRequired,
    label: PropTypes.string,
    placeholder: PropTypes.string,
    type: PropTypes.string,
    isSearch: PropTypes.bool,
    onChange: PropTypes.func.isRequired,
    onBlur: PropTypes.func,
    onFocus: PropTypes.func,
    multiline: PropTypes.bool,
    autoFocus: PropTypes.bool,
    InputProps: PropTypes.object,
    disabled: PropTypes.bool,
    autoComplete: PropTypes.string,
    allowNegative: PropTypes.bool,
    labelProps: PropTypes.object
};

export default withStyles(styles)(InputGroup);

I hope someone can advise what the issue is and how to overcome it.

Normally when we pass data from parent, we consider it to be Immutable , (ie) It should not be changed directly from the child components .

So, what one could do is use the prop value directly from the parent and use a method to mutate or change from the parent .

Below code is self explanatory.

Parent

class Parent {

  // parent immutable state
  public parentObject: object = {
     location: "",
     phoneNo: ""
  };

  constructor() {
    this.state = {
       parentObject: this.parentObject
    }
  }


  public onParentObjectChangeCallBack(key: string, value: string | number) {
    this.state.parentObject[key] = value;
    // to rerender
    this.setState();
  }

  public render () {
    return <ChildComponent parentObject={this.state.parentObject} 
           onChange={this.onParentObjectChangeCallBack} />
  }

}

Child

class ChildComponent {
  @Prop
  public parentObject: object;

  @Prop
  public onChange: Function;

  public render() {
     <div>
        {
          this.parentObject.keys.map((key) => {
            return <div>
                     <span> {{key}}</span>
                     // calls parent method to change the immutable object
                     <input value={{this.parentObject[key]}} onChange=(val) => 
                            this.onChange(key, val) />
                   </div>
          })
        }
     </div>


  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM