使用 React Hooks 的依赖下拉菜单

Dependent Dropdown with React Hooks

我是 React 的新手,一直很难实现这个依赖下拉菜单。我想获取状态列表并过滤掉呈现到第二个下拉列表的位置。以下是我尝试实施的内容。状态和位置数据来自 API.

我能够提取状态数据,但在实现依赖下拉菜单时卡住了。任何帮助将不胜感激。

import React, { useState, useEffect } from 'react'

function NullView() {

    // //API CALL
    const [error, setError] = useState(null);
    const [isLoaded, setIsLoaded] = useState(false);
    const [items, setItems] = useState([]);

    const [state, setState] = useState(null);
    const [locations, setLocations] = useState([])
    // console.log(count)
    let loadLocations = (e) => {
        e.preventDefault();

    }

    useEffect(() => {
        fetch("/api/merchant/all/states/")
            .then(res => res.json())
            .then((result) => {
                setIsLoaded(true);
                setItems(result);
            },
                (error) => {
                    setIsLoaded(true);
                    setError(error);
                }
            )
        if (state != null) {
            fetch("/api/merchant/locations/2/")
                .then(res => res.json())
                .then((result) => {
                    setIsLoaded(true);
                    setLocations(result);
                },
                    (error) => {
                        setIsLoaded(true);
                        setError(error);
                    }
                )
        }


    }, [])


    return (
        <div>
            <form onChange={loadLocations}>
                <label for="states">Choose a State:</label>
                <select id="states" name="states" onChange={(e) => setState(e.target.value)}>
                    <option value="">Select State</option>

                    {items.map(states => (

                        <option key={states.id} value={states.id}>{states.name}</option>
                    ))}

                </select>


                <label for="location">Choose a Location:</label>
                <select id="location" name="location" onChange={(e) => setLocation(e.target.value)}>
                    <option value="">Select Location</option>

                    {Location.map(location => (

                        <option key={location.id} value={location.id}>{location.name}</option>
                    ))}

                </select>

            </form>

        </div>
    )
}

export default NullView

试试这个

import React, { useState, useEffect } from 'react'

function NullView() {

    // //API CALL
    const [error, setError] = useState(null);
    const [isLoaded, setIsLoaded] = useState(false);
    const [items, setItems] = useState([]);

    const [state, setState] = useState(null);
    const [locations, setLocations] = useState([])
    //i set api location in state
    const [apiLocation, setAPILocation] = useState(`/api/merchant/locations/`)
    // console.log(count)
    let loadLocations = (e) => {
        e.preventDefault();

    }

    useEffect(() => {
        fetch("/api/merchant/all/states/")
            .then(res => res.json())
            .then((result) => {
                setIsLoaded(true);
                setItems(result);
            },
                (error) => {
                    setIsLoaded(true);
                    setError(error);
                }
            )
        fetch(apiLocation)
            .then(res => res.json())
            .then((result) => {
                setIsLoaded(true);
                setLocations(result);
            },
                (error) => {
                    setIsLoaded(true);
                    setError(error);
                }
            )


    }, [])

    checkUrlLocation(url, newValue) {
      let splited = url.split('/')
      splited[splited.length - 1] = newValue
      return splited.join('/')

    }

    return (
        <div>
            <form onChange={loadLocations}>
                <label for="states">Choose a State:</label>
                <select id="states" name="states" onChange={(e) =>{
                    /* in this case, if you select i states, it will put state id in api location and re-run useEffect */
                    setAPILocation(checkUrlLocation(apiLocation,e.target.value))
                    setState(e.target.value)
                  }
                } >
                    <option value="">Select State</option>

                    {items.map(states => (

                        <option key={states.id} value={states.id}>{states.name}</option>
                    ))}

                </select>


                <label for="location">Choose a Location:</label>
                <select id="location" name="location" onChange={(e) => setLocation(e.target.value)}>
                    <option value="">Select Location</option>

                    {locations.map(location => (

                        <option key={location.id} value={location.id}>{location.name}</option>
                    ))}

                </select>

            </form>

        </div>
    )
}

export default NullView

您可以将两次提取分成单独的 useEffect 回调。第一个 useEffect 回调获取组件安装并更新“状态”选项,而第二个 useEffect 依赖于当前选择的“状态”值。

useEffect(() => {
  fetch("/api/merchant/all/states/")
    .then((res) => res.json())
    .then((result) => setItems(result))
    .catch((error) => setError(error))
    .finally(() => setIsLoaded(true));
}, []); // <-- fetch once when component mounts

useEffect(() => {
  if (state) {
    fetch(`/api/merchant/locations/${state}`) // <-- compute request URL
      .then((res) => res.json())
      .then((result) => setLocations(result))
      .catch((error) => setError(error))
      .finally(() => setIsLoaded(true));
  }
}, [state]); // <-- fetch when state updates

我相信您的渲染中也有错字,Location 应该是 locations 状态。

return (
  <div>
    <form onChange={loadLocations}>
      <label for="states">Choose a State:</label>
      <select
        id="states"
        name="states"
        onChange={(e) => setState(e.target.value)}
      >
        <option value="">Select State</option>
        {items.map((states) => (
          <option key={states.id} value={states.id}>
            {states.name}
          </option>
        ))}
      </select>

      <label for="location">Choose a Location:</label>
      <select
        id="location"
        name="location"
        onChange={(e) => setLocation(e.target.value)}
      >
        <option value="">Select Location</option>
        {locations.map((location) => ( // <-- render locations state
          <option key={location.id} value={location.id}>
            {location.name}
          </option>
        ))}
      </select>
    </form>
  </div>
);