我有一个包含两个部分的图库照片应用。 “图库” 部分和“选择” 部分。 图库部分中的每张照片都有一个添加到购物车按钮。按下该特定照片后,该照片会添加到选择部分,其中有多个选项可供选择,每个选项都有一个输入框,用于输入 Quantity (数量)(如下图所示)。
我的问题是,当我键入数量(每种类型)时,应用会重新绘制,移至页面顶部,并失去对特定输入的关注。
查看此gif以查看我在说什么
下面是组件(不包括导入和不相关的代码)。
当按下添加到购物车时,调用handleAddSelection
并导致以以下格式将照片对象添加到selectedPhotos
阵列状态,然后在< strong>选择部分。
{
"path": "/client-photos/8/Esau Silva-3678-ytht6745.jpg",
"label": "ytht6745.jpg",
"packages": [
{
"optionID": 9,
"description": "1-11x14",
"price": 25,
"type": "Individual Sheets",
"quantity": 0
},
{
"optionID": 8,
"description": "1-16x10",
"price": 35,
"type": "Individual Sheets",
"quantity": 0
},
...
]
}
当我在每个软件包选项的输入框中之一中输入数字时,我会呼叫handleUpdateSelection
。
import produce from 'immer';
const ClientPhotos = () => {
const [client, setClient] = useState({});
const [isLoading, setIsLoading] = useState(false);
const [isError, setIsError] = useState(false);
const [selectedPhotos, setSelectedPhotos] = useState([]);
const { slug } = useParams();
useEffect(() => {
// Load photos
const fetchClient = async () => {
...
setClient(photos);
...
}
}, [slug]);
const handleAddSelection = photo => {
const packages = client.packageOptions.map(p => ({
...p,
quantity: 0,
}));
const photoObject = {
...photo,
packages,
};
setSelectedPhotos([...selectedPhotos, photoObject]);
};
const handleRemoveSelection = (e, photoLabel) => { ... };
const handleUpdateSelection = (e, option, selectionIndex, packageIndex) => {
const quantity = e.target.value;
const { optionID } = option;
// Get the specific photo from the state array
const selection = selectedPhotos[selectionIndex];
// Now update the quantity for the specific package in the selected photo
const nextState = produce(selection, draft => {
draft.packages[packageIndex].quantity = quantity;
});
// Finally update the app state array
setSelectedPhotos(
produce(selectedPhotos, draft => {
draft[selectionIndex] = nextState;
}),
);
};
const Render = () => {
return (
<div className="container container-extended">
<h1>{client.name} Photos</h1>
<PhotoGallery
photos={client.photos}
handleAddSelection={handleAddSelection}
/>
<PackageOptions />
</div>
);
};
const PackageOptions = () => {
return (
<section className="packages-content">
<h2>Selections</h2>
{selectedPhotos.map(({ label, packages }, selectionIndex) => (
<Fragment key={label}>
<div className="row">
<div className="col-md-3">
<p className="photo-label d-flex justify-content-between">
<strong>{label}</strong>
<button
type="button"
title="Delete Selection"
onClick={e => handleRemoveSelection(e, label)}
>
<i className="fas fa-trash-alt"></i>
</button>
</p>
</div>
<div className="col">
<Table borderless hover responsive>
<thead>
<tr>
<th>Package Options</th>
<th>Price</th>
<th>Quantity</th>
</tr>
</thead>
<tbody>
{packages.map((p, packageIndex) => (
<tr key={p.optionID}>
<td>{p.description}</td>
<td>{currencyFormatter.format(p.price)}</td>
<td>
<Input
className="quantity"
onKeyPress={numbersOnly}
onChange={e =>
handleUpdateSelection(e,p,selectionIndex,packageIndex,)
}
value={packages[packageIndex].quantity}
/>
</td>
</tr>
))}
</tbody>
</Table>
</div>
</div>
<hr />
</Fragment>
))}
</section>
);
};
return (
<>
{isError && <Alert color={alertTypes.Danger}>Something went wrong</Alert>}
{isLoading ? <Spinner /> : <Render />}
</>
);
};
const processLabel = photo => { ... };
const processData = data => { ... };
然后,在每种类型的数量输入之后,整个页面都会重新呈现,从而失去对输入的关注,并移至页面顶部。
有人可以指出正确的方向吗?我不希望整个页面重新呈现,也不希望失去对特定输入的关注。
谢谢
答案 0 :(得分:0)
以供将来参考
我能够通过切换到类组件来解决我的问题。我想是有问题的,我的状态数据结构无法配合。
我怀疑是因为useState
替换了整个特定状态,并导致整个页面重新呈现。与this.setState
合并状态相反。
现在唯一重新渲染的是输入?