子コンポーネント内にあるのtotal
合計をレンダリングする親コンポーネントが1つありsubtotals
ます。
function Total({ products }) {
const [total, setTotal] = useState(0);
const handleChildToParent = (subtotal) => {
setTotal(total + subtotal);
};
return (
<div>
{products.map((product) => (
<Subtotal product={product} childToParent={handleChildToParent} />
))}
<span>Total: {total}</span>
</div>
);
}
各Subtotal
コンポーネントはアイテムの価格を受け取り、ユーザーが選択したユニット数に基づいて小計を計算します。
function Subtotal({ product, childToParent }) {
const [units, setUnits] = useState(0);
const handleInputChange = (value) => {
setUnits(value);
childToParent(value * product.price);
};
return (
<div>
<input
type="number"
min={1}
onChange={(e) => handleInputChange(e.target.value)}
value={units}
/>
<span>units * product price: {units * product.price}</span>
</div>
);
}
私の目標は、子の情報に基づいて、親コンポーネントに動的な合計を含めることです。例:ユーザーがそれぞれ100ドルの価格で2つのアイテムを選択し、12ドルの価格で3つを選択すると、親コンポーネントは236ドルを表示し、子コンポーネントは最初のアイテムに200ドル(100x2ドル)を表示し、36ドル(12x3ドル)を表示する必要があります。 2番目のアイテム(これは私が現在持っているものです)、そしてユーザーが最初のアイテムに気が変わって、2つではなく1つだけを取得したい場合、合計価格は$ 136に更新されるはずです。アイテムを差し引こうとすると、行き詰まります。アイテムの初期合計を設定し、useEffectを合計で使用しようとしましたが、解決策が得られません。コンポーネント間の子から親への通信を使用してこれが本当に可能かどうかは実際にはわかりません。
これが私が持っているもののサンドボックスです:https://codesandbox.io/s/reverent-elbakyan-i0hr1
これは、「小計」コンポーネントから親に「状態を持ち上げる」必要がある典型的な例です。
多くの場合、複数のコンポーネントが同じ変化するデータを反映する必要があります。共有状態を最も近い共通の祖先まで持ち上げることをお勧めします。
この場合、「いくつかのコンポーネントが同じ変更データを反映する必要がある」場所は、あなた<Total>
が言ったように、あなたのコンポーネントです。
私の目標は、子の情報に基づいて、親コンポーネントに動的な合計を含めることです。
Reactのコアパターンの1つは、「データが流れ落ちる」ことです。言い換えると、データ/状態はアプリ内で高レベルで存在し、そこから子孫に「フローダウン」する必要があります。データを「子」コンポーネント(<Subtotal>
)内に配置し、その祖先の状態も更新しようとすることは、Reactのアンチパターンであり、一度に2つ以上の場所で同じ状態を追跡することを意味するため、避ける必要があります。
次のようなものを試してください。
function Total({ products }) {
// track "subtotals" in one place in state;
// the total value of all subtotals can be trivially derived from this
const [subtotals, setSubtotals] = React.useState(new Array(products.length).fill(0));
// our onChange handler will update the index of "subtotals"
// with the passed new value
const onChange = (newValue, i) => {
setSubtotals(oldSubtotals => {
const newSubtotals = [...oldSubtotals];
newSubtotals[i] = newValue;
return newSubtotals;
});
}
let total = 0;
for (let i = 0; i < subtotals.length; i++) {
total += subtotals[i] * products[i].price;
}
return (
<div>
{products.map((product, i) => (
<Subtotal product={product} value={subtotals[i]} onChange={onChange} index={i} />
))}
<span>Total: {total}</span>
</div>
);
}
// now <Subtotal> tracks no state, it is entirely stateless;
// it simply displays the correct information and calls its onChange as needed
function Subtotal({ product, value, onChange, index }) {
return (
<div>
<input
type="number"
// updated min to 0, unless you really want to force
// them to buy at least one...?
min={0}
onChange={(e) => onChange(e.target.value, index)}
value={value}
/>
<span>units * product price: {value * product.price}</span>
</div>
);
}
さて、合計値が何であるかについての真実の源であり<Total>
、唯一<Total>
です。1つのコンポーネントが他のコンポーネントの状態をミラーリングしようとしているという奇妙な状態の分割はありません。<Total>
各小計が追跡している値を正確に把握し、その値を子コンポーネントと、その状態を更新する関数に渡すだけです。しかし、あなたは2つの場所で状態を追跡していません。これは、非常に悪いことです。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加