我是反应打字稿的新手,我在更新表单时遇到了麻烦,该表单有 5 个要更新的字段(名称、图像、价格、数量、信息)。我正在尝试更新字段并已从 redux store 设置字段。我没有使用 useState 更新本地,而是尝试直接更新商店(从我获取数据的位置),然后提交表单。使用 updateProductState reducer ,我尝试更新值字段。但它没有更新而是设置为“名称:名称” 但商店数据没有更新。 谢谢你
下面是代码 产品切片.ts: `导出接口 ProductState { 加载:布尔值; 产品:产品型号[]; 所选产品:产品型号; 错误:字符串; }
export let initialState: ProductState = {
loading: false,
products: [] as ProductModel[],
selectedProduct: {} as ProductModel,
error: ''
};
export const productSlice = createSlice( {
name: 'product',
initialState,
reducers: {
**updateProductState**: ( state, action ) =>
{
const { id, name, image, price, qty, info } = action.payload;
return {
...state,
selectedProduct: {
id,
name,
image,
price,
qty,
info,
} as ProductModel,
};
}
}
**UpdateProduct.ts:
**
import React, { useEffect, useState } from 'react';
import { useDispatch,useSelector } from 'react-redux';
import { useParams} from 'react-router-dom';
import { AppDispatch } from '../../../../redux/store';
import * as productActions from '../../../../redux/productsSlice';
import { useNavigate } from 'react-router';
interface IProps{ }
interface IState
{
bigBasket: productActions.ProductState;
}
type URLParams=
{
productId: string;
}
const UpdateProduct: React.FC<IProps> = ( { } ) =>
{
let dispatch = useDispatch<AppDispatch>();
const { productId } = useParams<URLParams>();
const navigate = useNavigate()
let productState: productActions.ProductState = useSelector( ( store: IState ) => store.bigBasket )
let { error, loading, selectedProduct } = productState;
useEffect( () =>
{
dispatch( productActions.getSingleProductThunk( productId as string) );
}, [productId] )
** let updateInput = (event:React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) =>
{
dispatch( productActions.updateProductState( {
name: event.target.name,
value:event.target.value
} ))}**
let updateImage = async (event:React.ChangeEvent<HTMLInputElement | any>) => {
let imageFile:Blob = event.target.files[0];
let base64Image:string | ArrayBuffer = await convertBase64String(imageFile);
dispatch( productActions.updateProductState(
{name: "image", value:base64Image }
) );
};
let convertBase64String = (imageFile:Blob):Promise<string | ArrayBuffer> => {
return new Promise((resolve, reject) => {
let fileReader = new FileReader();
fileReader.readAsDataURL(imageFile);
fileReader.addEventListener('load', () => {
if(fileReader.result){
resolve(fileReader.result);
}
else {
reject('Error Occurred');
}
})
});
};
let submitUpdateProduct = ( event: React.FormEvent<HTMLFormElement> ) =>
{
event.preventDefault();
dispatch( productActions.updateProductThunk( { product: selectedProduct, productId: productId as string, navigate } ) );
}
return (
<React.Fragment>
{ <pre>{ JSON.stringify( selectedProduct ) }</pre> }
<section className='mt-3'>
<div className="container">
<div className="row">
<div className="col-md-4">
<div className="card">
<div className="card-header bg-secondary bg-white">
<p className="h4 text-white">Update Product</p>
</div>
<div className="card-body rgba-green-light">
<form onSubmit={submitUpdateProduct}>
<div className="mb-3">
<input
required
name="name"
value={selectedProduct.name}
onChange={updateInput}
type="text" className="form-control" placeholder="Name"/>
</div>
<div className="mb-3">
<input
onChange={updateImage}
className="form-control" type="file" id="formFile"/>
{
selectedProduct.image &&
<img src={selectedProduct.image} alt="" width="25" height="25"/>
}
</div>
<div className="mb-3">
<input required type="number"
name="price"
value={selectedProduct.price}
onChange={ updateInput }
className='form-control' placeholder="Price"/>
</div>
<div className="mb-3">
<input required type="number"
name="qty"
value={selectedProduct.qty}
onChange={ updateInput }
className='form-control' placeholder='Available Quantity'/>
</div>
<div className="mb-3">
<textarea required name="info"
value={selectedProduct.info}
onChange={ updateInput }
rows={ 3 } className='form-control' placeholder="General Info" />
</div>
<div className="" >
<input type="submit" className="btn btn-secondary btn-sm" value="Update"/>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</section>
</React.Fragment>
) }
导出默认UpdateProduct`
updateInput
处理程序正在分派 updateProductState
操作并传递正在更新的字段名称和值,但 updateProductState
缩减器正在访问它假定的整个字段值集。
更新
updateProductState
缩减器以访问 action.payload.name
作为要更新为 action.payload.value
值的状态中的字段/属性的名称。
interface UpdateProductStatePayload { // *
name: keyof ProductModel; // "id", "name", "image", "price", "qty", "info"
value: string;
}
*注意:根据需要调整此接口以满足您的实际状态/类型/等有效负载需求。
export const productSlice = createSlice( {
name: 'product',
initialState,
reducers: {
updateProductState: (state, action: PayloadAction<UpdateProductStatePayload>) => {
const { name, value } = action.payload;
return {
...state,
selectedProduct: {
...state.selectedProduct,
[name]: value,
},
};
},
},
};
或者因为您可以使用以下内容编写可变状态更新:
export const productSlice = createSlice( {
name: 'product',
initialState,
reducers: {
updateProductState: (state, action: PayloadAction<UpdateProductStatePayload>) => {
const { name, value } = action.payload;
state.selectedProduct[name] = value;
},
},
};