为什么在调度 redux 操作后组件状态为空?

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

我正在尝试通过去抖来实现产品列表和搜索功能,但是 在 ProductList 组件中执行分派操作后,SearchProducts 组件的状态 search 为空。有人可以建议下面的代码有什么问题吗?

产品列表

import { fetchData } from "../../services/productService";
import { useDispatch, useSelector } from "react-redux";
import {
  fetchProductInfo,
} from "../../store/features/productsSlice";
import ToastContext from "../../context/ToastContext";
import "bootstrap-icons/font/bootstrap-icons.css";
import { useNavigate } from "react-router-dom";
import { FETCH_PRODUCTS_END_URL } from "../../utils/constant";
import SearchProducts from "./SearchProducts";
import SearchBox from "./SearchBox";

const ProductList = () => {
  const navigate = useNavigate();
  const toastCtx = useContext(ToastContext);
  const dispatch = useDispatch();
  const { products, loading, error, status } = useSelector(
    (state) => state.products
  );

  const [keySearch, SearchForm] = useForm('');

  useEffect(() => {
    dispatch(fetchProducts());
  }, []);

  if (loading) {
    return <h2>Products is loading ....</h2>;
  }
  if (error) {
    return <h2>{error}</h2>;
  }
  return (
    <div className="container mt-2">
      <h1 className="text-center mt-4">Products List</h1>
     <SearchProducts /> 
      <table className="table mt-4">
        <thead>
          <tr>
            <th scope="col">Name</th>
            <th scope="col">Category</th>
            <th scope="col">Price</th>
          </tr>
        </thead>
        <tbody>
          {products.length > 0 &&
            products.map((product) => {
              return (
                <tr key={product._id}>
                  <td className="col">{product.name}</td>
                  <td className="col">{product.category}</td>
                  <td className="col">{product.price}</td>
                </tr>
              );
            })}
          {products.length === 0 && (
            <tr>
              <td className="text-center" colSpan="4">
                <strong>No products available !!</strong>
              </td>
            </tr>
          )}
        </tbody>
      </table>
    </div>
  );
};

export default ProductList;

搜索产品

import { useDispatch } from "react-redux";
import { searchProducts } from "../../store/features/productsSlice";

const SearchProducts = (props) => {
  const [search, setSearch] = useState("");
  const dispatch = useDispatch();

  let seacrhClick = useCallback(() => {
    if(search.length > 0){
      dispatch(searchProducts(search));
    }
  }, [search]);

  useEffect(() => {
    let timerID = setTimeout(() => {
      seacrhClick();
    }, 1000);
    return () => {
      clearTimeout(timerID);
    };
  }, [search]);

  return (
    <div className="container">
      <input
        key={`search_${search}`}
        className="w-50 form-control"
        type="text"
        name="search"
        autoFocus
        value={search || ''}
        placeholder="Search Products"
        onChange={(e) => {
          setSearch(e.target.value);
        }}
      />
    </div>
  );
};

export default SearchProducts;

redux 中的 searchProduct 功能

export const searchProducts = (key) => {
  return async (dispatch,getState) => {
    try {
      dispatch(setStatus(PRODUCTS_STATUS.REQUESTED));
      dispatch(setLoading(true));
      const response = await fetchData(`${PRODUCTS_SEARCH_URL}/${key}`);
      dispatch(setStatus(PRODUCTS_STATUS.SUCCESS));
      dispatch(setLoading(false));
      dispatch(setProducts(response?.data));
    } catch (err) {
      dispatch(
        setError(
          err?.response?.data?.message
            ? err?.response?.data?.message
            : err.message
        )
      );
      dispatch(setLoading(false));
      dispatch(setStatus(PRODUCTS_STATUS.FAILED));
    }
  }
}

enter image description here

reactjs redux
1个回答
0
投票

当您主动搜索时,即调度

searchProducts
操作时,
ProductList
组件有条件地呈现一些替代 UI。这意味着
SearchProducts
已卸载。当搜索后
loading
error
状态再次为 false 时,
SearchProducts
会重新挂载,再次使用默认初始状态。

重构渲染的 UI 以保持

SearchProducts
的安装。

重构示例:

const ProductList = () => {
  const dispatch = useDispatch();
  const { products, loading, error, status } = useSelector(
    (state) => state.products
  );

  useEffect(() => {
    dispatch(fetchProducts());
  }, []);

  return (
    <div className="container mt-2">
      <h1 className="text-center mt-4">Products List</h1>

      <SearchProducts />

      {loading
        ? <h2>Products is loading ....</h2>
        : (
          <>
            {error && <h2>{error}</h2>}
            <table className="table mt-4">
              <thead>
                <tr>
                  <th scope="col">Name</th>
                  <th scope="col">Category</th>
                  <th scope="col">Price</th>
                </tr>
              </thead>
              <tbody>
                {products.length
                  ? products.map((product) => (
                    <tr key={product._id}>
                      <td className="col">{product.name}</td>
                      <td className="col">{product.category}</td>
                      <td className="col">{product.price}</td>
                    </tr>
                  ))
                  : (
                    <tr>
                      <td className="text-center" colSpan="4">
                        <strong>No products available !!</strong>
                      </td>
                    </tr>
                  )
                }
              </tbody>
            </table>
          </>
        )
      }
    </div>
  );
};
最新问题
© www.soinside.com 2019 - 2024. All rights reserved.