Состояние совместного использования дочернего компонента с родителем? - PullRequest
0 голосов
/ 06 сентября 2018

Я довольно новичок в React и немного борюсь со своим первым заданием.

Я создаю общий компонент TextBox (из MaterialUI) и создал дочерний компонент (NumberInput), который расширяет TextBox. Проблема в том, что всякий раз, когда я набираю какой-либо ввод в NumberInput, состояние NumberInput, похоже, не обновляется. Любые советы будут оценены!

Родитель:

import React, { Component } from 'react';
import TextField from '@material-ui/core/TextField';
import { Validations } from './validations'
import PropTypes from 'prop-types';

class TextBox extends Component {
    constructor(props) {
        super(props);

        this.state = {
            value: null,
            error: false,
            errorMsg: null
        };

    this.setValue = this.setValue.bind(this);
    this.setError = this.setError.bind(this);
    this.setErrorMsg = this.setErrorMsg.bind(this);
    this.handleChange = this.handleChange.bind(this);
    this.checkForErrors = this.checkForErrors.bind(this);

}

// Handles changes upon each edit of the textbox. Updates the state value and checks for errors.
handleChange(event) {
    this.setValue(event);
}

setValue(event) {
    var value = document.getElementById(this.props.id).value;
    this.setState({ value: value }, () => this.checkForErrors());
}

setError(error, errorMsg) {
    this.setState({ error: error });
    this.setErrorMsg(errorMsg);
}

setErrorMsg(errorMsg) { this.setState({ errorMsg: errorMsg }) }

getValue() { return this.state.value }

getError() { return this.state.error }

getErrorMsg() { return this.state.errorMsg }

// Checks for input error
checkForErrors() {
    var input = this.getValue();
    console.log(input);
    var validations = Validations(this.props, input);
    this.setError(validations.error, validations.errorMsg);
}

render() {
    let {
        label,
        placeholder,
        maxLength,
        minLength,
        maxNumber,
        minNumber,
        disabled,
        required,
        type,
        multiline,
        id,
        name,
        allowSpecialCharacters,
        allowWhitespace
    } = this.props;

    return (
        <div>
            <br/>
            <TextField
                error = { this.getError() }
                label = { label }
                helperText = { this.getErrorMsg() }
                placeholder = { placeholder }
                inputProps = {{ maxLength: maxLength }}
                disabled = { disabled }
                required = { required }
                type = { type }
                multiline = { multiline }
                onChange = { this.handleChange }
                id = { id }
                name = { name }
            />
        </div>
    );
 }
};

TextBox.propTypes = {
    label: PropTypes.string,
    helperText: PropTypes.string,
    placeholder: PropTypes.string,
    maxLength: PropTypes.number,
    minLength: PropTypes.number,
    maxNumber: PropTypes.number,
    minNumber: PropTypes.number,
    disabled: PropTypes.bool,
    required: PropTypes.bool,
    type: PropTypes.oneOf(["button", "checkbox", "color", "date", "datetime-local", "email", "file",
    "hidden", "image", "month", "number", "password", "radio", "range", "reset", "search",
        "submit", "tel", "text", "time", "url", "week"]),
    multiline: PropTypes.bool,
    id: PropTypes.string,
    name: PropTypes.string,
    allowSpecialCharacters: PropTypes.bool,
    allowWhitespace: PropTypes.bool
}

TextBox.defaultProps = {
    label: '',
    helperText: '',
    placeholder: '',
    maxLength: 100000,
    minLength: 0,
    maxNumber: 100000,
    minNumber: -100000,
    disabled: false,
    required: false,
    type: 'text',
    multiline: false,
    id: 'input',
    name: '',
    allowSpecialCharacters: true,
    allowWhitespace: true   
}

export default TextBox;

Ребенок:

import React, { Component } from 'react';
import TextBox from './textbox';
import { Validations } from './validations'
import PropTypes from 'prop-types';

// const NumberInput = props => {
//  return (
//      <TextBox {...props} type="number" />
//  )
// }

class NumberInput extends TextBox {

    constructor(props) {
        super(props);

        this.state = {
            value: null,
            error: false,
            errorMsg: null
        };  
    }

    render() {

        return (
            <div>
                <TextBox
                    label = { "NumberInput" }
                    type = { "number" }             
                />
            </div>
        )

    }
};

export default NumberInput;

App.js

import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import TextBox from './widgets/textbox/textbox';
import TextArea from './widgets/textbox/textarea';
import NumberInput from './widgets/textbox/numberinput';

class App extends Component { 
  render() {
    return (
      <div className="App">
        <header className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <h1 className="App-title">Welcome to React</h1>
        </header>
        <p className="App-intro">
          To get started, edit <code>src/App.js</code> and save to 
  reload.
        </p>
        <TextBox type="text" label={"Textbox"} />
        <NumberInput label={"NumberInput"} />
      </div>
    );
  }
}

export default App;

Обновлено NumberInput:

const NumberInput = props => {
    return (
        <TextBox {...props} type="number" id="inp" />
    )
}

1 Ответ

0 голосов
/ 06 сентября 2018

Вам не нужно использовать здесь класс для вашего дочернего компонента и расширять его от родительского. Этот процесс очень прост, когда вы передаете свою функцию-обработчик вашему дочернему компоненту.

class Parent extends React.Component {
  state = {
    value: "initial value",
  }

  handleChange = e => this.setState({ value: e.target.value });

  render() {
    return (
      <div>
        <p>Change the value:</p>
        <Child onChange={this.handleChange} value={this.state.value} />
        <p>{JSON.stringify(this.state.value)}</p>
      </div>
    );
  }
}

const Child = props => {
  return (
    <input onChange={props.onChange} value={props.value} />
  )
}

ReactDOM.render(<Parent />, document.getElementById("root"));
<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>
<div id="root"></div>
...