Я пытаюсь создать свое первое простое внешнее приложение CRUD в React. У меня проблемы с формой редактирования.
Всякий раз, когда я отображаю форму редактирования с полями, заполненными значениями выбранной записи, мне нужно редактировать каждое поле, чтобы сохранить его обратно в базу данных. Если я не изменю ни одно из значений полей, включая идентификатор записи, или изменю только одно значение, я получаю сообщение об ошибке:
[GraphQL error]: Message: could not convert string to float: , Location: undefined, Path: undefined
.
Я знаю, что могу добавить Mutation
в Query
, но тогда у меня возникают проблемы с повторной загрузкой обновленного списка записей в родительском компоненте, и я все еще получаю сообщение об ошибке, упомянутое выше.
export class EditForm extends Component {
constructor(props) {
super(props);
this.state = {
id: '',
name: '',
price: '',
category: ''
};
this.handleInputChange = this.handleInputChange.bind(this);
}
handleInputChange = (event) => {
const target = event.target;
const value = target.value;
const name = target.name;
this.setState({
[name]: value
});
};
updateSome = async () => {
const {id, name, price, category} = this.state;
await this.props.editOne({
variables: {
id,
name,
price,
category
},
refetchQueries: [{ query: ones }]
})
};
render() {
return (
<div>
<Query query = {GET_ONE} variables = {{one: Number(this.props.id)}}>
{({ loading, error, data, networkStatus }) => {
if (loading) return "Loading...";
if (error) return `Error! ${error.message}`;
if (networkStatus === 4) return "Refetching!";
return (
<div>
{data.ones.map(one => (
<Form key = {one.id}>
<Row>
<Col>
<Form.Group>
<Form.Label>ID</Form.Label>
<Form.Control
name='id'
defaultValue = {one.id}
onChange = {this.handleInputChange}
type = "text"
placeholder = "id"
/>
</Form.Group>
</Col>
<Col>
<Form.Group>
<Form.Label>Name</Form.Label>
<Form.Control
name='name'
defaultValue = {one.name}
onChange = {this.handleInputChange}
type = "text"
placeholder = "name"
/>
</Form.Group>
</Col>
<Col>
<Form.Group>
<Form.Label>Price</Form.Label>
<Form.Control
name='price'
defaultValue = {one.price}
onChange = {this.handleInputChange}
type = "number"
step = {0.01}
placeholder = "price"
/>
</Form.Group>
</Col>
<Col>
<Form.Group>
<Form.Label>Category</Form.Label>
<Query query = {twos}>
{({loading, error, data}) => {
if (loading) return <Spinner animation = "border" role = "status">
<span className = "sr-only">Loading...</span>
</Spinner>;
if (error) return `Error! ${error.message}`;
return (
<Form.Control name='category'
defaultValue = {one.category.id}
onChange = {this.handleInputChange}
as = "select"
placeholder = "category"
>
{data.twos.map(two => (
<option key = {two.id} value = {two.id}>{two.category}</option>
))}
</Form.Control>
);
}}
</Query>
</Form.Group>
</Col>
</Row>
<ButtonToolbar>
<Button
variant = "primary"
onClick = {() => this.updateSome()}
>Update</Button>
</ButtonToolbar>
</Form>
))}
</div>
);
}}
</Query>
</div>
)
}
}
Как присвоить начальные значения выбранной записи this.state.id
, this.state.name
и т. д. после отображения Component
? Я знаю, как ввести некоторые значения в this.state в constructor
вручную, но я хочу передать значения, отображаемые в полях формы, в this.state
.
Вы, наверное, знаете, что использование setState
вызывает повторную визуализацию и обновление в компоненте <Query/>
. Компонент формы (с обработкой состояния и событий) должен быть помещен внутри <Query/>
, чтобы избежать этого эффекта - getDerivedStateFromProps()
для начального состояния.
В этом случае без рефакторинга достаточно условноsetState
в render
, например:
<Query query = {GET_ONE} variables = {{one: Number(this.props.id)}}>
{({ loading, error, data, networkStatus }) => {
if (loading) return "Loading...";
if (error) return `Error! ${error.message}`;
if (networkStatus === 4) return "Refetching!";
// one-time flag, it can be undefined/uninitialized
if (!this.state.initialized) {
this.setState( {
initialized: true, // block this block
id: data.someField,
name: data.someField,
price: data.someField,
category: data.someField
})
}
return (
Ошибка GraphQL, вероятно, относится к полю price
, преобразовать типы в variables
(внутри вызова this.props.editOne
).
data.ones[0].id
? console.info(data)
?
Вы, конечно, знаете, что используете (сохраняете в состоянии) один набор переменных для множества записей... перезаписывая друг друга? Вероятно, вам нужен массив в состоянии для сохранения значений для всех записей.
Я вполне понимаю вашу точку зрения, но я не уверен, как добраться до полей моей формы здесь. Простая ссылка не будет принята React, поэтому это должно быть что-то другое. Я пытался получить данные из Query, но что-то вроде data.ones.indexOf(0).id не дает мне идентификатор записи.