Ad

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.

Ad

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).

Ad
source: stackoverflow.com
Ad