从子组件更新反应状态(对象数组)

aso*_*tos 9 javascript reactjs

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

我有以下代码

家长:

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;

Run Code Online (Sandbox Code Playgroud)

孩子:

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;
Run Code Online (Sandbox Code Playgroud)

Kos*_*asX 6

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

家长:

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;
Run Code Online (Sandbox Code Playgroud)

孩子:

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;
Run Code Online (Sandbox Code Playgroud)
  • 随着您的前进,这可能会变得非常复杂,因此最好的选择是寻找某种状态管理解决方案,例如使用Context API

  • 另外,看看这篇有趣的文章,其中讨论了使用map索引值作为key值:索引作为键是一种反模式


完整源代码:

import React from 'react';
import ReactDOM from 'react-dom';
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>
    );
}

function Update({ data }) {
    const [ expenses, setExpenses ] = useState(data);
    return (
        <div>
            { 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;
ReactDOM.render( 
  <Update data={[
    {
    description:"Title 1",
    date: "2018",
    credit: "100",
    debit: "debit"
    },
    {
      description:"Title 2",
      date: "2019",
      credit: "199",
      debit: "card"
      }
    ]} />, 
  document.querySelector("#root") 
);
Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Run Code Online (Sandbox Code Playgroud)