使用redux工具包创建一个reducer来更新react Typescript中表单中的多个字段

问题描述 投票:0回答:1

我是反应打字稿的新手,我在更新表单时遇到了麻烦,该表单有 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`

reactjs typescript updates redux-toolkit
1个回答
0
投票

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;
    },
  },
};
© www.soinside.com 2019 - 2024. All rights reserved.