在我自己的可重用组件中包装一个 TextField

Wrapping a TextField in my own reusable component

所以我有一个组件,它在输入的文本开头添加了一个 *,如下所示:

 export default class MyTextField extends Component {

      constructor() {
    super();
    this.state = {
      value: '',
    };
  }

  static propTypes = {
    onChange: PropTypes.func,
    value: PropTypes.string
  }

  addSymbol(newValue, symbol) {
    return newValue.indexOf(symbol) === -1 ? `${symbol}${newValue}` : newValue;
  }

  change(input, newValue) {
    console.log(`I am the parent wit newValue ${newValue}.`);
    this.setState({
      value: this.addSymbol(newValue, '*')
    });
  }

  render() {
    const {
      onChange, // eslint-disable-line no-unused-vars
      ...other
    } = this.props;

    return (
      <TextField
        value={this.state.value}
        onChange={this.change.bind(this)}
        {...other } >
      </TextField >
    );
  }
}

现在我在另一个组件中使用 MyTextField,如下所示:

 <MyTextField
    style={styleTextFields}
    floatingLabelText='Add text'
    type='text'
  />

现在,当我开始输入时,一切都很好。

如果我更改上面的代码并在 MyTextField 上添加 value='test' prop,一切都会中断。它出现是因为我在 TextField 中添加了一个 prop,它不能被 MyTextField value={this.state.value} 覆盖。

那么我怎样才能添加 prop value 并且仍然在输入文本的开头添加 *

另一部分是,如果用户添加了自己的 onChange,我怎样才能同时调用 MyTextField 和使用 MyTextField onChange 事件的组件?

=======编辑 1 的开始===============

@Patrick - 我已根据您的评论进行了调整,第一部分现在正在运行。所以我可以输入 <TextField /> 并看到更改。

变化如下:

export default class MyTextField extends Component {
      constructor(props) {
    super();
    this.state = {
      value: props.value ? this.addSymbol(props.value.toString(), '*') : ''
    };
  }

  static propTypes = {
    onChange: PropTypes.func,
    value: PropTypes.string
  }

  addSymbol(newValue, symbol) {
    return newValue.indexOf(symbol) === -1 ? `${symbol}${newValue}` : newValue;
  }

  change(input, newValue) {
    console.log(`I am the parent wit newValue ${newValue}.`);
    this.setState({
      value: this.addSymbol(newValue, '*')
    });
  }

  render() {
    const {
      value, // eslint-disable-line no-unused-vars
      onChange, // eslint-disable-line no-unused-vars
      ...other
  } = this.props;

    return (
      <TextField
        value={this.state.value}
        onChange={this.change.bind(this)}
        {...other } >
      </TextField >
    );
  }
}

我不确定如何进行 onChange 调整,因为您不应该修改组件状态?

我也在 render() 函数中尝试过这个,但它不起作用:

  addSymbol(newValue, symbol) {
    return newValue.indexOf(symbol) === -1 ? `${symbol}${newValue}` : newValue;
  }

  change(input, newValue) {
    console.log(`I am the parent wit newValue ${newValue}.`);
    this.setState({
      value: this.addSymbol(newValue, '*')
    });
  }

  render() {
    const {
      value, // eslint-disable-line no-unused-vars
      onChange, // eslint-disable-line no-unused-vars
      ...other
  } = this.props;

    return (
      <TextField
        value={this.addSymbol(this.state.value, '*')}
        {...other } >
      </TextField >
    );
  }

无论如何,谢谢你的帮助。

=======编辑 1 结束===============

=======编辑 2 的开始===============

我通过添加我自己的名为 onNewValueChange 的事件并在 onChange 中调用它来修复 onChange 事件问题。这是最终代码:

export default class MyTextField extends Component {

      constructor() {
    super();
    this.state = {
      value: props.value ? this.addSymbol(props.value.toString(), '*') : ''
    };
  }

  static propTypes = {
    onNewValueChange: PropTypes.func,
    value: PropTypes.string
  }

  addSymbol(newValue, symbol) {
    return newValue.indexOf(symbol) === -1 ? `${symbol}${newValue}` : newValue;
  }

  change(input, newValue) {
    const value = value: props.value ? this.addSymbol(props.value.toString(), '*') : '';
    this.setState({
      value: value
    });

    if(this.props.onNewValueChange) {
        this.props.onNewValueChange(value);
    }
  }

  render() {
    const {
      onNewValueChange, // eslint-disable-line no-unused-vars
      ...other
    } = this.props;

    return (
      <TextField
        value={this.state.value}
        onChange={this.change.bind(this)}
        {...other } >
      </TextField >
    );
  }
}

现在我在另一个组件中使用 MyTextField,如下所示:

<MyTextField
    style={styleTextFields}
    floatingLabelText='Add text'
    type='text'
    onNewValueChange={(newValue) => console.log(newValue) }
  />

@Patrick 谢谢你的帮助,让我朝着正确的方向前进。

=======编辑 2 结束===============

总的来说,我认为这种在组件内部传递所有其他内容之前省略 props 的模式令人困惑,至少对我而言。尽可能明确应该始终是一个优先事项。

如果我理解正确,预期的行为如下:

  1. 您可以传递默认文本,您的组件应在该文本前加上 * 前缀。
  2. 您可以修改文本,但无论您如何修改,都应始终以 * 为前缀 - 因此空字符串应该只是 *。

我创建了这个 fiddle 希望它能达到您的意思:https://jsfiddle.net/69z2wepo/78041/

关键概念是将 props 和 state 分开,一个 prop 只传递一次,并且应该真正负责你的初始状态

这是我创建的两个 类:

class Input extends React.Component{
  render(){
   return (<input onChange={this.props.onChange} value={this.props.value}/>)
  }
}

class WrappedInput extends React.Component{

  constructor(props){
      super();

    let val = props.value || '';
    this.state = {
        value : this.addSymbol(val,'*')
    }
  }

  handleChange(e){
    let newVal = e.target.value;
    this.setState({value:this.addSymbol(newVal,'*')});
  }

  addSymbol(newValue, symbol) {
    return newValue.indexOf(symbol) === -1 ? `${symbol}${newValue}` : newValue;
  }

  render(){
   return (<Input onChange={this.handleChange.bind(this)} value={this.state.value}/>)
  }
}