17370845950

React中动态点击分类触发Axios API调用的最佳实践

本文旨在解决在react应用中通过点击不同分类元素来触发动态api调用的常见问题。重点阐述了`

  • `元素`value`属性的误用,并提供了两种正确且语义化的解决方案:利用`

    最直接且语义化的解决方案是使用

    代码示例:

    import React, { useState, useEffect } from 'react';
    import axios from 'axios';
    
    const API_BASE_URL = "https://www.themealdb.com/api/json/v1/1/filter.php?c="; // 示例API
    
    function CategoryFilter() {
      const [category, setCategory] = useState("Seafood"); // 初始分类
      const [meals, setMeals] = useState([]);
      const [error, setError] = useState(null);
      const [loading, setLoading] = useState(false);
    
      useEffect(() => {
        if (!category) return; // 如果没有分类,则不发起请求
    
        setLoading(true);
        setError(null);
        axios
          .get(`${API_BASE_URL}${category}`)
          .then(function (response) {
            setMeals(response.data.meals || []); // 确保即使没有数据也设置为空数组
          })
          .catch(function (err) {
            console.error("API Error:", err);
            setError("加载数据失败,请稍后再试。");
            setMeals([]);
          })
          .finally(() => {
            setLoading(false);
          });
      }, [category]); // category 改变时重新运行 effect
    
      const onClickHandler = (e: React.MouseEvent) => {
        // 使用 e.currentTarget.value 获取 button 的值
        setCategory(e.currentTarget.value);
      };
    
      return (
        
          

    菜品分类

    {loading &&

    加载中...

    } {error &&

    {error}

    } {!loading && !error && meals.length === 0 &&

    未找到相关菜品。

    } {!loading && !error && meals.length > 0 && (

    {category} 菜品:

      {meals.map((meal: any) => (
    • {meal.strMeal}
    • ))}
    )} ); } export default CategoryFilter;

    注意事项:

    • 在onClickHandler中,我们使用e.currentTarget.value来获取按钮的值。currentTarget指的是事件监听器所绑定的元素,而target可能是事件实际发生的元素(例如,如果按钮内有文本,target可能是文本节点)。对于按钮,两者通常相同,但currentTarget在处理事件委托时更可靠。
    • 将button嵌套在li中是完全符合语义的,因为li代表列表项,而button是列表项中的一个可交互元素。

    解决方案二:使用 data-* 属性(如果必须使用

  • 如果出于某种设计或结构上的考虑,你坚持要让

  • 元素本身作为可点击项,并且需要传递自定义数据,那么HTML5的data-*属性是理想的选择。data-*属性允许你在标准HTML元素上存储自定义数据,而不会影响其语义或行为。

    代码示例:

    import React, { useState, useEffect } from 'react';
    import axios from 'axios';
    
    const API_BASE_URL = "https://www.themealdb.com/api/json/v1/1/filter.php?c="; // 示例API
    
    function CategoryFilterWithDataAttribute() {
      const [category, setCategory] = useState("Seafood"); // 初始分类
      const [meals, setMeals] = useState([]);
      const [error, setError] = useState(null);
      const [loading, setLoading] = useState(false);
    
      useEffect(() => {
        if (!category) return;
    
        setLoading(true);
        setError(null);
        axios
          .get(`${API_BASE_URL}${category}`)
          .then(function (response) {
            setMeals(response.data.meals || []);
          })
          .catch(function (err) {
            console.error("API Error:", err);
            setError("加载数据失败,请稍后再试。");
            setMeals([]);
          })
          .finally(() => {
            setLoading(false);
          });
      }, [category]);
    
      const onClickHandler = (e: React.MouseEvent) => {
        // 使用 e.currentTarget.getAttribute("data-value") 获取自定义数据
        const clickedCategory = e.currentTarget.getAttribute("data-value");
        if (clickedCategory) {
          setCategory(clickedCategory);
        }
      };
    
      return (
        
          

    菜品分类 (使用 data-value)

    • 海鲜 (Seafood)
    • 素食 (Vegetarian)
    • 甜点 (Dessert)
    {loading &&

    加载中...

    } {error &&

    {error}

    } {!loading && !error && meals.length === 0 &&

    未找到相关菜品。

    } {!loading && !error && meals.length > 0 && (

    {category} 菜品:

      {meals.map((meal: any) => (
    • {meal.strMeal}
    • ))}
    )} ); } export default CategoryFilterWithDataAttribute;

    注意事项:

    • 在HTML中,data-*属性的命名规则是data-前缀后跟自定义名称(如data-value)。
    • 在JavaScript中,你可以通过元素的dataset属性(e.currentTarget.dataset.value)或getAttribute()方法(e.currentTarget.getAttribute("data-value"))来访问这些数据。dataset属性提供了一个更方便的DOMStringMap接口,将data-value转换为dataset.value。
    • 被用作可点击元素时,为了提高用户体验和可访问性,建议为其添加cursor: pointer样式,并考虑添加键盘导航支持。

    总结

    在React应用中实现动态API调用时,选择正确的HTML元素和属性至关重要。

    1. 首选 当你需要一个可点击的交互元素来触发动作并传递值时,
    2. *`data-属性作为备选:** 如果你必须使用非表单元素(如
    3. 、等)作为可点击项,并且需要关联自定义数据,那么data-*`属性是最佳方案。它允许你在不违反HTML语义的前提下存储额外信息。
    4. 避免误用
    5. 的value属性:
    6. 记住
    7. 的value属性仅用于指定有序列表中的序数值,不应用于存储自定义字符串数据。
    8. 通过遵循这些最佳实践,你可以构建出更健壮、更易维护且用户体验更好的React应用。