通知反应组件的价值变化

时间:2016-12-14 15:52:24

标签: javascript reactjs

假设我有一个组件类负责将输入文本框的任何数字更改为文字

class NumbersToText extends Component {

  onChange(event) {
    const { target } = event;
    const { value } = target;

    if (hasNumbers(value)) {
      target.value = numbersToText(value);
      // HERE I NEED TO NOTIFY ABOUT CHANGES
    }
  }

  render() {
    return (
      <span onChange={this.onChange}>
        {this.props.children}
      </span>
    );
  }
}

现在用法看起来像这样:

<NumbersToText>
  <input onChange={this.saveValue}
</NumbersToText>

让我们说一切正常,价值变为文字。

现在问题是在我将数字更改为文本并将该值分配给输入onChange之后,处理程序不会再次执行,因此不会使用更新的值调用saveValue

如何使用新值触发onChange处理程序来解决此问题?

3 个答案:

答案 0 :(得分:0)

我不确切地知道numbers to text到底是什么意思所以我假设您想在输入中调用onChange函数之前修改该值,并在输入中反映该值。

首先,你正在做的事情永远不会在React上运行,React将内部virtual对象反映到DOM中,这意味着你不应该直接修改DOM,而应该修改这个内部表示(通过setState) ,props)将此更改反映到DOM中。

React还有两种类型的输入,控制和非控制。我假设你想在不受控制的输入上使用它。

我能看到的唯一可行解决方案是使用React.cloneElement函数转换输入,在调用输入的onChange回调之前添加一个附加步骤。

这是一个可能使输入变为大写的实现。

class UpperCase extends React.Component {
    constructor(props) {
      super(props);            
    }

    onChange(e, input, next) {
      let value = input.value || '';
      value = value.toUpperCase();
      input.value = value;
      next(value);
    }

    render() {
      let childs = React.Children.map(this.props.children, child => {
        let input = null; //Will take advantage of javascript's closures
        let onChangeChild = child.props.onChange.bind(child);
        return React.cloneElement(child, { 
            ref: ref => input = ref,
            onChange: e => {
              this.onChange(e, input, onChangeChild)
            }
        });
      });
      return (
        <span>
            {childs}
        </span>
      );
    }
}

你可以像这样使用它:

<UpperCase>
  <input onChange={(val) => console.log(val)}></input>  
  <textarea onChange={(val) => console.log(val)}></textarea>  
</UpperCase>

答案 1 :(得分:0)

感谢@tiagohngl,我想出了一个类似的,但也许不那么杂乱(没有克隆元素)的方式:

class NumbersToText extends Component {

  onChange(event) {
    const { target } = event;
    const { value } = target;

    if (hasNumbers(value)) {
      target.value = numbersToText(value);

      this.childrenOnChange(event);
    }
  }

  childrenOnChange(event) {
    const { children } = this.props;

    React.Children.forEach(children, child => {
      if (child.props.onChange) {
        child.props.onChange(event);
      }
    });
  }

  render() {
    return (
      <span onChange={this.onChange}>
        {this.props.children}
      </span>
    );
  }
}

答案 2 :(得分:0)

export default class NumbersToText extends React.Component {

constructor(props) {
    super(props)
    this.onChange = this.onChange.bind(this);
}

componentWillMount() {
    this.setState({ anyData: [] });
}

onChange(event) {
    this.setState({anyData: event.target.value},
    ()=>{console.log("AnyData: "+this.state.anyData)});
    // callback to console.log after setState is done
}

render() {
    return (
        <input type="text"
            value={this.state.anyData}
            onChange={this.onChange} />
        );
    }
}

如你所说, 更改后的值不会调用onChange。

有多种可能性。

  1. onChange没有绑定。

  2. 渲染方法没有状态更改,因此不会重新渲染

  3. 使用console.log()来追踪问题

  4. 我稍微修改了代码以供说明。

    希望它有所帮助。

    How react handle State Change (answer I posted before)