我想从子组件更新父状态,该子组件将呈现对象数组的每个对象。子组件的主要目标是从对象数组中更新原始值。

我有以下代码

上级:

import { useState } from 'react';
import ExpenseItem from './expenseItem';

function Update({ data }) {
    const [ expenses, setExpenses ] = useState(data);
    return (
        <div>
            {expenses.map((expense, index) => {
                return <ExpenseItem key={index} {...expense} />;
            })}
            <button>Save</button>
        </div>
    );
}

export default Update;



儿童:

import { useState, useRef } from 'react';

function ExpenseItem({ description, date, credit, debit }) {
    const [ edit, setEdit ] = useState(false);
    const [ expenseDescription, setExpenseDescription ] = useState(description);
    const textInput = useRef();
    const renderDefaultView = () => {
        return <h3 onDoubleClick={() => setEdit(true)}>{expenseDescription}</h3>;
    };
    const renderEditView = () => {
        return (
            <div>
                <input
                    type="text"
                    ref={textInput}
                    defaultValue={expenseDescription}
                    onDoubleClick={() => setEdit(true)}
                />
                <button onClick={() => setEdit(false)}>X</button>
                <button onClick={() => updateValue()}>OK</button>
            </div>
        );
    };
    const updateValue = () => {
        const value = textInput.current.value;
        setExpenseDescription(value);
        textInput.current.defaultValue = value;
        setEdit(false);
    };
    return (
        <div>
            {edit ? renderEditView() : renderDefaultView()}
            <span>{date}</span>
            <p>{debit}</p>
            <p>{credit}</p>
        </div>
    );
}

export default ExpenseItem;

最佳答案

一种方法是通过道具将父状态属性(expenses)和将其更新的函数(setExpenses)传递给子组件:

上级:

import React from 'react';
import ReactDOM from 'react-dom';

import { useState } from 'react';
import ExpenseItem from './ExpenseItem';

function Update({ data }) {
    const [ expenses, setExpenses ] = useState(data);
    return (
        <div>
            Checking: { expenses[0].description } | { expenses[1].description }
            <hr/>
            {expenses.map((expense, index) => {
                return <ExpenseItem key={index} index={index} expenses={expenses} setExpenses={setExpenses} />;
            })}
            <button>Save</button>
        </div>
        );
}

export default Update;


儿童::

import React from 'react';
import { useState, useRef } from 'react';

function ExpenseItem( props ) {
    let { description, date, credit, debit } = props.expenses[props.index];
    const setExpenses = props.setExpenses;
    const [ edit, setEdit ] = useState(false);
    const [ expenseDescription, setExpenseDescription ] = useState(description);
    const textInput = useRef();
    const renderDefaultView = () => {
        return <h3 onDoubleClick={() => setEdit(true)}>{expenseDescription}</h3>;
    };
    const renderEditView = () => {
        return (
            <div>
                <input
                    type="text"
                    ref={textInput}
                    defaultValue={expenseDescription}
                    onDoubleClick={() => setEdit(true)}
                />
                <button onClick={() => setEdit(false)}>X</button>
                <button onClick={() => updateValue()}>OK</button>
            </div>
        );
    };
    const updateValue = () => {
        const value = textInput.current.value;
        setExpenseDescription(value);
        textInput.current.defaultValue = value;
        setEdit(false);
        const expenses = [ ...props.expenses ]; // Get a copy of the expenses array
        // Replace the current expense item
        expenses.splice( props.index, 1, {
            description: value, date, credit, debit
        });
       // Update the parent state
        setExpenses( expenses );

    };
    return (
        <div>
            {edit ? renderEditView() : renderDefaultView()}
            <span>{date}</span>
            <p>{debit}</p>
            <p>{credit}</p>
        </div>
    );
}

export default ExpenseItem;


Working demo


当您前进时,这可能会变得非常复杂,因此最好的选择是寻找某种状态管理解决方案,例如使用Context API
另外,请看一下这篇有趣的文章,该文章讨论将map索引值用作key值:Index as a key is an anti-pattern

08-08 03:10