How Do I Assign Values To States Once I Open My Edit Form?
I'm trying to create my first simple CRUD front-end app in React. I have some problems with the edit form.
Whenever I display the edit form with fields filled with values of a chosen record, I need to edit each of the field in order to save it back to the database. If I don't change any of the fields values - including the id of a record - or change only one value, I get the error:
[GraphQL error]: Message: could not convert string to float: , Location: undefined, Path: undefined
.
I am aware of the fact, that I can add Mutation
in Query
but then I get problems with refetching the updated list of records in the parent component and still get the error message mentioned above.
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>
)
}
}
How do I assign initial values of a chosen record to this.state.id
, this.state.name
and so on, once the Component
is displayed? I know how to enter some values to this.state in constructor
by hand, but I want to pass the values that are displayed in the form fields to this.state
.
Answer
You probably know that using setState
forces rerender and refetch in <Query/>
component. Form component (with state and event handling) should be placed inside <Query/>
to avoid that effect - getDerivedStateFromProps()
for initial state.
In this case, wthout refactoring it's enough to conditionallysetState
in render
, sth like:
<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 error probably refers to a price
field, convert types in variables
(within this.props.editOne
call).
Related Questions
- → Import statement and Babel
- → should I choose reactjs+f7 or f7+vue.js?
- → Uncaught TypeError: Cannot read property '__SECRET_DOM_DO_NOT_USE_OR_YOU_WILL_BE_FIRED' of undefined
- → .tsx webpack compile fails: Unexpected token <
- → React-router: Passing props to children
- → ListView.DataSource looping data for React Native
- → React Native with visual studio 2015 IDE
- → Can't test submit handler in React component
- → React + Flux - How to avoid global variable
- → Webpack, React & Babel, not rendering DOM
- → How do I determine if a new ReactJS session and/or Browser session has started?
- → Alt @decorators in React-Native
- → How to dynamically add class to parent div of focused input field?