Amini
Amini

Reputation: 1792

Updated - Changing the state from a functional child component

I have three components which App is the parent component(class-based) and two children component(functional-based) named User & Input. I've imported User to App and Input to User. I want to change the name by the value in Input(there is a button -> onClick).

Updated The problem is the function in App.jsx(I'm pretty sure the way I try to do it is true).

// App.jsx
Imported User

state = {
    users : [
        {id: 1, fullName: 'Amirreza Amini'},
        {id: 2, fullName: 'John Smith'},
        ...
    ]
};

handleChangeName = name => {
    const editedUsers = [...this.state.users];
    const users = editedUsers.map(user => user.fullName = name);

    this.setState({ users });
};

render() {
    const { users } = this.state;

    const userComponent = users.map(user => (

        <User
            key={user.id}
            fullName={user.fullName}
            edit={() => this.handleChangeName(user.fullName)}
        />

    ));
  

.

// User.jsx
Imported Input

const User = ({ fullName }) => {
    return (
        <section>
            <h1>{ fullName }</h1>

            <Input fullName={fullName} />
        </section>
    );
};

export default User;

.

// Input.jsx

const Input = ({ fullName }) => {
    return (
        <section>
            {/* The value of this input must be the fullName after I clicked the button */}
            <input className="user-edit-input" placeholder={fullName} />
            
            <button className="edit-button" onClick={edit(document.querySelector('.user-edit-input').value)}>Change</button>
        </section>
    );
};

export default Input;

Upvotes: 0

Views: 50

Answers (2)

Noam Yizraeli
Noam Yizraeli

Reputation: 5444

Two big options as I see it:

Option one is changing App.jsx to functional component and send the function to change the fullname to User.jsx and the to Input.jsx as props letting the Input component change the value by itself

Option two that can leave your App.jsx component as is, keep it more secured and allow the child component to deal with only what it needs to actually know, is similarly sending a function from the parent App component so the Input component can trigger sending the old fullname and new fullname and the parent component function would handle the rest of the process.

example for parent function:

const updateFullname = (previousName, newName) => {
    // Get previous object data and location in array
    let originalUsersState = this.state.users;
    let originalUser = originalUsersState.filter(
        (user, index) => user.fullName === previousName
    )
    const originalUserIndex = originalUsersState.findIndex(
        (user, index) => user.fullName === previousName
    )
    
    // Create new updated object and insert it to updated object array
    let updatedUser = originalUser
    updatedUser.fullName = newName;
    let updatedUsersState = originalUsersState;
    updatedUsersState[originalUserIndex] = updatedUser;

    // Update the state with the new updated object array
    this.setState(
        {
            users: updatedUsersState
        }
    );
}

Abbriviation for a solution for the question code with the new proposed function and process:

// App.jsx
Imported User

state = {
    users : [
        {id: 1, fullName: 'Amirreza Amini'},
        {id: 2, fullName: 'John Smith'},
        ...
    ]
};

handleChangeName = name => {
    const editedUsers = [...this.state.users];
    const users = editedUsers.map(user => user.fullName = name);

    this.setState({ users });
};

const updateFullname = (previousName, newName) => {
    // Get previous object data and location in array
    let originalUsersState = this.state.users;
    let originalUser = originalUsersState.filter(
        (user, index) => user.fullName === previousName
    )
    const originalUserIndex = originalUsersState.findIndex(
        (user, index) => user.fullName === previousName
    )

    // Create new updated object and insert it to updated object array
    let updatedUser = originalUser
    updatedUser.fullName = newName;
    let updatedUsersState = originalUsersState;
    updatedUsersState[originalUserIndex] = updatedUser;

    // Update the state with the new updated object array
    this.setState(
        {
            users: updatedUsersState
        }
    );
}

render() {
    const { users } = this.state;

    const userComponent = users.map(user => (

        <User
            key={user.id}
            fullName={user.fullName}
            updateFullname={updateFullname} 
            edit={() => this.handleChangeName(user.fullName)}
        />

    ));
// User.jsx
Imported Input

const User = ({ fullName, updateFullname }) => {
    return (
        <section>
            <h1>{ fullName }</h1>

            <Input fullName={fullName} updateFullname={updateFullname} />
        </section>
    );
};

export default User;
// Input.jsx

const Input = ({ fullName }) => {
    const [inputValue, setInputValue] = useState(undefined);

    return (
        <section>
            <input className="user-edit-input" value={inputValue} onChange={event => setInputValue(event.target.value)} placeholder={fullName} />
            
            <button className="edit-button" onClick={(fullname, inputValue) => updateFullname}>Change</button>
        </section>
    );
};

export default Input;

Upvotes: 1

Byrisetti Hemanth
Byrisetti Hemanth

Reputation: 202

You can send input as props to callback from User component. From Users, with the callback function, call one more function to set state in User component

Upvotes: 1

Related Questions