#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
должно быть значение для поля ввода.