не удается ввести в поле ввода react

#javascript #reactjs #typescript #react-native #react-props

Вопрос:

В настоящее время значение по умолчанию в моем поле ввода равно 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")}
 

каждый раз, когда я пытался ввести в поле ввода, я видел, как в консоли печатается «привет», но значение поля ввода по-прежнему не меняется.

Редактировать:

Это был код 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;
 

При изменении значения ввода линия на графике изменяется в соответствии со значением. Мне пришлось изменить этот код на машинописный. Это то, что у меня есть сейчас.

 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;   
 

хотя он компилируется без ошибок, функция ввода значения не работает. Это не изменяет линию на графике, поэтому я предполагаю, что состояние не сохраняется. Как я могу это исправить?

Комментарии:

1. Я не знаю, почему пример кода JS хранит и обновляет одни и те же значения, используя как реквизиты, так и состояние. Кажется, что это должно быть одно или другое. Вы можете либо отказаться от реквизитов (вам понадобится начальное значение в вашем компоненте), либо отказаться от состояния и позволить ему полностью контролироваться родителем.

2. Также странно, что setOrders функция принимает аргументы в виде массива, а не объекта. Они преобразуются из объекта в массив и обратно в объект. github.com/MenesesGHZ/polynomial-regression-js/blob/master/src/…

3. Не могли бы вы, пожалуйста, помочь мне, написав ответ? Я давно не работал в React и, кажется, кое-что забыл 🙁 @LindaPaiste, Кстати, хороший улов для рекордеров!

Ответ №1:

Проблема в том, что вы используете значение order_graph_1 и order_graph_2 , которое вы получаете от реквизитов, но обновляете те, которые у вас есть в состоянии, а не обновляете те, которые находятся в реквизитах.

Код, который вы преобразуете, обновляет как состояние, так и реквизиты (путем вызова this.props.setOrders ). Но совершенно необязательно иметь эти переменные в состоянии компонента RegressionSetup вообще, так как он уже может получить доступ к ним и обновить их с помощью реквизитов.

setOrders Функция, которая передается от родительского Main компонента, также немного глупа, потому что оба компонента имеют состояние со свойствами order_graph_1 и order_graph_2 -так почему мы передаем их в виде кортежа setOrders ?

В 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 не нужно использовать методы состояния, крючков или жизненного цикла. Он просто берет реквизит и возвращает JSX.

Я по-прежнему предпочитаю отображать два входа с помощью функции, так как это меньше повторений, но, очевидно, вам не нужно этого делать. Мы используем переменную property , чтобы получить правильное свойство из реквизита value={this.props[property]} и установить правильный ключ для объекта, которому мы передаем setOrders : onChange={(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>
    );
  }
}
 

Ссылка на песочницу Кода

Я также повозился с другими компонентами. Я добавил Props и State типы для всего. Я также использовал функции со стрелками, чтобы избавиться от всех bind(this) вызовов. Все еще есть несколько ошибок машинописи, связанных с внешними пакетами (chart.js и mathjs).

Ответ №2:

Компонент React повторно отправляется только при изменении состояния. Поэтому вы должны изменять состояние в соответствии со значением поля ввода каждый раз, когда значение изменяется, а затем просто загружать это значение состояния в поле ввода.

Ответ №3:

Это вызывает проблему value={this.props.order_graph_1} Значение здесь выводится из реквизитов, а не из состояния. В идеале он должен быть заполнен с использованием некоторого состояния, и onChange должен обновить это состояние. Так как после каждого повторного запроса реквизит не изменится, а входное значение останется прежним.

this.state.order_graph_1 должно быть значение для поля ввода.