1

I am trying to update the values in the form in child component to send to the api if I update an user but I am unable to change any values in the form and it only add or removes one character if I see the states. How can I update the values? using defaultValue solves it but it changes the input to be uncontrolled which i do not want.

...
#Parent Class
                import React from "react";
                import "./styles.css";
                import Child from "./child";

                export default class Parent extends React.Component {
                  constructor() {
                    super();
                    this.state = {
                      user: {
                        id: [1, 2, 3, 4, 5],
                        name: ["john", "wick", "ellen", "fork", "gow"]
                      }
                    };
                  }

                  render() {
                    return <Child user={this.state.user}> </Child>;
                  }
                }
               #Child Class
                import React from "react";
                import "./styles.css";

                export default class Child extends React.Component {
                  constructor(props) {
                    super(props);
                    this.state = {
                      user: {
                        id: "",
                        name: ""
                      }
                    };
                  }

                  handleSubmit = e => {
                    e.preventDefault();
                  };

                  handleChange = e => {
                    const data = { ...this.state.user };
                    data[e.currentTarget.name] = e.currentTarget.value;
                    this.setState({ user: data });
                  };

                  render() {
                    console.log(this.state);
                    console.log(this.props);
                    return (
                      <>
                        {this.props.user.id.map((id, index) => {
                          return (
                            <form onSubmit={this.handleSubmit}>
                              <label> id </label>
                              <input
                                type="text"
                                value={
                                  this.props.user.id[index] !== "undefined"
                                    ? this.props.user.id[index]
                                    : this.state.user.id
                                }
                                onChange={this.handleChange}
                              />
                              <br />
                              <label> name </label>
                              <input
                                type="text"
                                value={
                                  this.props.user.name[index] !== "undefined"
                                    ? this.props.user.name[index]
                                    : this.state.user.name
                                }
                                onChange={this.handleChange}
                              />
                            </form>
                          );
                        })}
                        }
                      </>
                    );
                  }
                }
...

my sample code is

https://codesandbox.io/s/focused-shamir-y85v9?file=/src/parent.js:0

3
  • Are you trying to change the local component state? or do you want the source of truth in the parent component to be updated? Have you tried using an single array of "user objects, i.e. { id: ###, name: 'XXX' }, with a handler defined in parent to be passed to children components? Commented Jun 7, 2020 at 23:30
  • yes, I did try that but it was changing the state as a whole. I want to update the data for the respective user in my case Commented Jun 8, 2020 at 2:52
  • Yes, all this would do is combine the user data you're trying to change so you don't have to keep track of which input goes to what array. If you assign a name attribute to all the inputs it becomes a trivial matter to match an input with a data field in a user object in state by index. Commented Jun 8, 2020 at 6:30

2 Answers 2

1

EDIT: Heres a revised version of your code on codesandbox

https://codesandbox.io/s/quizzical-dew-jhx1b

Original:

So there are a few issues here. Firstly, instead of directly displaying the user values from props, I would store those in the state in the constructor.

For Example

class MyApp extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      users: props.users
    }
  }
  ...

Then you can modify the state based on index. However, the way your data is organized is based on array indices which isn't the best. Instead, I would make each user an object

const myUser = {
  id: 1,
  name: 'John'
}

If the data you receive is already in that format, then you can parse it like so:

const ids = [1,2,3,4];
const names = ['John','Jenny','Jasper','Jaclyn'];

const users = ids.map((id, i) => ({ id, name: names[i] })); // uses arrow syntax

So the way your project is set up, you ARE modifying the state, however, you AREN'T displaying the state. (Because the id of the users in props never is undefined, lines 37,48 of your code)

So try parsing them into the state and then editing them based on the object index in the array, which will help keep the associated ids and names together without them getting mixed up.

Sign up to request clarification or add additional context in comments.

3 Comments

yep, I have already tried it but did not work for me. for the scope of the example i used arrays but in the main application, i am using objects
can you try to change in the codesandbox version? if it's possible?
done! let me know if you need explanation and I can add comments.
0

It's because, in handleChange, e.currentTarget.name is always null. So, you are setting state with empty values. Not entirely sure what you want to do, but if you do this,

  handleChange = e => {
    this.setState({ ...this.state, user: { id: e.target.value } });
  };

you will see your id field update in your input boxes.

One thing you might consider is having your state handler be passed down from the parent, so each onChange will update the state. Then have your input props just be this.props.user.id[index].

If you provide what exactly you are trying to do, maybe I can be more help.

1 Comment

I tried to use it but it did not work. the same issue is there

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.