首页 > 解决方案 > 无法输入反应输入字段

问题描述

目前,我的输入字段的默认值为 1。如果我尝试在输入字段中输入内容,则不会发生任何变化。

interface Orders {
    order_graph_1: number;
    order_graph_2: number;
  }

  interface MyProps extends Orders {
    setOrders: (...args: any) => void; // function which takes args...??
  }

  interface MyState extends Orders {
    //otherProperty: string;
  }
  
      

class Setup extends React.Component<MyProps, MyState>{
    state = {
        order_graph_1: this.props.order_graph_1,
        order_graph_2: this.props.order_graph_2
      };
    
      // needs to be an arrow function to access `this` properly
      // could use ( event: React.ChangeEvent<HTMLInputElement>)
      // could avoid the assertion by passing the name as an argument
      setOrders = (event: any) => {

        this.setState((prevState) => ({
          ...prevState,
          [event.target.name]: parseInt(event.target.value)
        }));
      };
    render(){
        return(
            <div className="row">
                <div className="col-6">
                    <p className="text-center">Order of first model: </p>
                    <div className="w-100 d-flex justify-content-center">
                        <input className="text-center" name="order_graph_1" type="number" value={this.props.order_graph_1} onChange={this.setOrders.bind(this)} min="1" max="10"/>
                </div>
                </div>
            </div>
        );
    }
}

export default Setup;

为了测试,我取消了 onChange 函数

onChange={()=>console.log("hello")}

每次我尝试在输入字段中输入时,我都看到控制台中打印了 hello,但输入字段的值仍然没有改变。

编辑:

这是一个 JS 代码(https://github.com/MenesesGHZ/polynomial-regression-js):

class RegressionSetup extends React.Component{
    constructor(props){
        super(props);
        this.orders = {
            "order_graph_1":this.props.order_graph_1,
            "order_graph_2":this.props.order_graph_2
        }; 
    }
    
    setOrders(event){
        this.orders[event.target.name] = parseInt(event.target.value);
        this.props.setOrders(Object.values(this.orders));
    }

    render(){
        return(
            <div className="row">
                <div className="col-6">
                    <p className="text-center">Order of first model: </p>
                    <div className="w-100 d-flex justify-content-center">
                        <input className="text-center" name="order_graph_1" type="number" value={this.props.order_graph_1} onChange={this.setOrders.bind(this)} min="1" max="10"/>
                </div>
                </div>
                <div className="col-6">
                    <p className="text-center">Order of second model: </p>
                    <div className="w-100 d-flex justify-content-center">
                        <input className="text-center"name="order_graph_2" type="number" value={this.props.order_graph_2} onChange={this.setOrders.bind(this)} min="1" max="10"/>
                    </div>
                </div>
            </div>
        );
    }
}

export default RegressionSetup;

更改输入值后,图表上的一条线会根据该值更改。我不得不将此代码更改为 Typescript。这就是我现在所拥有的。

interface Orders {
    order_graph_1: number;
    order_graph_2: number;
  }

  interface MyProps extends Orders {
    setOrders: (...args: any) => void; // function which takes args...??
  }

  interface MyState extends Orders {
    //otherProperty: string;
  }
  
      

class Setup extends React.Component<MyProps, MyState>{
    state = {
        // it is best not to derive state from props
        order_graph_1: this.props.order_graph_1,
        order_graph_2: this.props.order_graph_2
      };
    
      // needs to be an arrow function to access `this` properly
      // could use ( event: React.ChangeEvent<HTMLInputElement>)
      // could avoid the assertion by passing the name as an argument
      setOrders = (event: any) => {
        // I don't love this solution, but we can avoid the TS errors by copying the previous state
        this.setState((prevState) => ({
          ...prevState,
          [event.target.name]: parseInt(event.target.value)
        }));
      };
    render(){
        return(
            <div className="row">
                <div className="col-6">
                    <p className="text-center">Order of first model: </p>
                    <div className="w-100 d-flex justify-content-center">
                        <input className="text-center" name="order_graph_1" type="number" value={this.state.order_graph_1} onChange={this.setOrders.bind(this)} min="1" max="10"/>
                </div>
                </div>
                {/* <div className="col-6">
                    <p className="text-center">Order of second model: </p>
                    <div className="w-100 d-flex justify-content-center">
                        <input className="text-center"name="order_graph_2" type="number" value={this.props.order_graph_2} onChange={this.setOrders.bind(this)} min="1" max="10"/>
                    </div>
                </div> */}
            </div>
        );
    }
}

export default Setup;   

虽然它编译没有错误,但输入值的东西不起作用。它不会改变图表上的线条,所以我假设状态没有保存。我怎样才能解决这个问题?

标签: javascriptreactjstypescriptreact-nativereact-props

解决方案


问题是您使用的是从道具中获得的值,order_graph_1order_graph_2更新了您在状态中的值,而不是更新道具中的值。

您正在转换的代码会更新状态和道具(通过调用this.props.setOrders)。但是完全没有必要让这些变量处于组件状态,RegressionSetup因为它已经可以通过 props 访问和更新它们。

从父setOrders组件向下传递的函数也有点傻,因为两个组件都有一个带有属性的状态,那么为什么我们将它们作为一个元组传递给? Mainorder_graph_1order_graph_2setOrders

您可以在其中Main删除该setOrders函数,而是向下传递一个调用setState.

<RegressionSetup
  order_graph_1={this.state.order_graph_1}
  order_graph_2={this.state.order_graph_2}
  setOrders={(orders) => this.setState(orders)}
/>

setState在类组件中采用部分新状态并将其与当前状态合并。这意味着我们甚至不必将两个订单都传递给setOrders. 我们只需一个订单就可以调用它,这很好。

所以我们可以RegressionComponent像这样定义道具:

export interface OrderGraphs {
  order_graph_1: number;
  order_graph_2: number;
}

interface Props extends OrderGraphs {
  setOrders(graphs: Partial<OrderGraphs>): void;
}

它没有理由成为类组件,但这也没关系。 RegressionSetup不需要使用状态、钩子或生命周期方法。它只需要 props 并返回 JSX。

我仍然更喜欢使用函数来呈现两个输入,因为它的重复性更少,但显然你不必这样做。我们使用该变量property从 props 中获取正确的属性,value={this.props[property]}并在我们传递给的对象上设置正确的键setOrdersonChange={(e) => this.props.setOrders({[property]: parseInt(e.target.value, 10)})}

class RegressionSetup extends React.Component<Props> {
  renderInput(property: keyof OrderGraphs, label: string) {
    return (
      <div className="col-6">
        <p className="text-center">{label}</p>
        <div className="w-100 d-flex justify-content-center">
          <input
            className="text-center"
            name={property}
            type="number"
            value={this.props[property]}
            onChange={(e) =>
              this.props.setOrders({ [property]: parseInt(e.target.value, 10) })
            }
            min="1"
            max="10"
            step="1"
          />
        </div>
      </div>
    );
  }

  render() {
    return (
      <div className="row">
        {this.renderInput("order_graph_1", "Order of first model: ")}
        {this.renderInput("order_graph_2", "Order of second model: ")}
      </div>
    );
  }
}

代码沙盒链接

我也弄乱了其他组件。我为所有内容添加PropsState类型。我还使用箭头函数来摆脱所有的bind(this)调用。仍然有一些与外部包(chart.js 和 mathjs)相关的 Typescript 错误。


推荐阅读