在不在父级中写入状态的情况下在反应中传递一个值
Passing a value up in react without writing state in parent
我想做什么:
我需要价格*数量=总数。我有一个 table,价格为 1,数量为 1,总计为 1。数量是一个计数器,需要有自己的状态,因为行将添加更多计数器。但我需要在父级 table 中使用该值,以便我可以使用它来计算总数。
通常我会将计数器值放在父级中,但如果我这样做,当我更改一个计数器时,它们都会改变。那么我还能如何将值传回父级呢?或者我这里还有什么其他选择。
//parent
const memoData = useMemo(() => {
return productList.map((product) => (
<tr key={product.productNumber} className='productTable__row'>
<td>
<input
placeholder='Product name'
className='productTable__input productTable__input_product'
defaultValue={product.productName}
/>
</td>
<td>
<input
placeholder='Id'
className='productTable__input productTable__input_id'
disabled
defaultValue={product.productNumber}
/>
</td>
<td>
<input
placeholder='Price'
className='productTable__input productTable__input_price'
defaultValue={product.price}
/>
</td>
<td>
<Input prouct={product} />
</td>
<td>
<input
placeholder='Total'
className='productTable__input productTable__input_price'
defaultValue={? * product.price}
/>
</td>
<td>
<button
className='productTable__btn_close'
onClick={() => onProductDelete(product)}
>
<RiCloseFill fill='red' size='30px' />
</button>
</td>
</tr>
));
}, [onProductDelete, currentProduct, productList]);
//child
function Input() {
const [counter, setCounter] = useState(1);
const addOneClick = () => {
setCounter(counter + 1);
};
const minusOneClick = () => {
if (counter > 0) {
setCounter(counter - 1);
}
};
return (
<div style={{ width: '88px' }}>
<button
className='productTable__btn_minus'
style={{ borderRight: 'none' }}
onClick={minusOneClick}
>
<FaMinus fill='var(--color-primary-blue)' size='14px' />
</button>
<input
placeholder='0'
className='productTable__input productTable__input_quantity'
// defaultValue={0}
value={counter}
/>
<button
className='productTable__btn_plus'
style={{ borderLeft: 'none' }}
onClick={addOneClick}
>
<FaPlus fill='var(--color-primary-blue)' size='14px' />
</button>
</div>
);
}
视觉参考:
您应该将 productList
视为父级中的“状态”,而不是 counter
,并且您应该将 counter
作为 [=14 的 属性 =]:
// productList
[
{
id: 123,
counter: 0, // <-- add a counter property
productNumber: '...',
// ...
},
]
// parent
return productList.map( product => (
<tr key={ product.productNumber } >
<td>
{/* add onSetCounter() callback */}
<Input
product={ product }
onSetCounter={ id => { setCounter( id, count ); } }
/>
</td>
</tr>
));
// child
function Input() {
const counter = props.product.counter; // <-- use props
const setCounter = props.setCounter; // <-- use props
// const [counter, setCounter] = useState(1); // <-- don't use local state
const addOneClick = () => {
setCounter(counter + 1);
};
return (
<button onClick={ addOneClick } >add one</button>
);
}
// update the counter
const setCounter = function( id, count ){
// ... I don't know how you are managing your productList.
// I would put this code into my redux-reducer. ...
const newProductList = productList.reduce( (acc, product) => {
if( product.id === id ){ // current product
acc.push({
...product,
counter: count
})
} else { // other products
acc.push( product );
};
}, []);
};
(我在这里写了props.product
,尽管你通过了<Input prouct={...} />
,我认为这是一个打字错误)
我想做什么: 我需要价格*数量=总数。我有一个 table,价格为 1,数量为 1,总计为 1。数量是一个计数器,需要有自己的状态,因为行将添加更多计数器。但我需要在父级 table 中使用该值,以便我可以使用它来计算总数。
通常我会将计数器值放在父级中,但如果我这样做,当我更改一个计数器时,它们都会改变。那么我还能如何将值传回父级呢?或者我这里还有什么其他选择。
//parent
const memoData = useMemo(() => {
return productList.map((product) => (
<tr key={product.productNumber} className='productTable__row'>
<td>
<input
placeholder='Product name'
className='productTable__input productTable__input_product'
defaultValue={product.productName}
/>
</td>
<td>
<input
placeholder='Id'
className='productTable__input productTable__input_id'
disabled
defaultValue={product.productNumber}
/>
</td>
<td>
<input
placeholder='Price'
className='productTable__input productTable__input_price'
defaultValue={product.price}
/>
</td>
<td>
<Input prouct={product} />
</td>
<td>
<input
placeholder='Total'
className='productTable__input productTable__input_price'
defaultValue={? * product.price}
/>
</td>
<td>
<button
className='productTable__btn_close'
onClick={() => onProductDelete(product)}
>
<RiCloseFill fill='red' size='30px' />
</button>
</td>
</tr>
));
}, [onProductDelete, currentProduct, productList]);
//child
function Input() {
const [counter, setCounter] = useState(1);
const addOneClick = () => {
setCounter(counter + 1);
};
const minusOneClick = () => {
if (counter > 0) {
setCounter(counter - 1);
}
};
return (
<div style={{ width: '88px' }}>
<button
className='productTable__btn_minus'
style={{ borderRight: 'none' }}
onClick={minusOneClick}
>
<FaMinus fill='var(--color-primary-blue)' size='14px' />
</button>
<input
placeholder='0'
className='productTable__input productTable__input_quantity'
// defaultValue={0}
value={counter}
/>
<button
className='productTable__btn_plus'
style={{ borderLeft: 'none' }}
onClick={addOneClick}
>
<FaPlus fill='var(--color-primary-blue)' size='14px' />
</button>
</div>
);
}
视觉参考:
您应该将 productList
视为父级中的“状态”,而不是 counter
,并且您应该将 counter
作为 [=14 的 属性 =]:
// productList
[
{
id: 123,
counter: 0, // <-- add a counter property
productNumber: '...',
// ...
},
]
// parent
return productList.map( product => (
<tr key={ product.productNumber } >
<td>
{/* add onSetCounter() callback */}
<Input
product={ product }
onSetCounter={ id => { setCounter( id, count ); } }
/>
</td>
</tr>
));
// child
function Input() {
const counter = props.product.counter; // <-- use props
const setCounter = props.setCounter; // <-- use props
// const [counter, setCounter] = useState(1); // <-- don't use local state
const addOneClick = () => {
setCounter(counter + 1);
};
return (
<button onClick={ addOneClick } >add one</button>
);
}
// update the counter
const setCounter = function( id, count ){
// ... I don't know how you are managing your productList.
// I would put this code into my redux-reducer. ...
const newProductList = productList.reduce( (acc, product) => {
if( product.id === id ){ // current product
acc.push({
...product,
counter: count
})
} else { // other products
acc.push( product );
};
}, []);
};
(我在这里写了props.product
,尽管你通过了<Input prouct={...} />
,我认为这是一个打字错误)