useEffect 和上下文 api

Posted

技术标签:

【中文标题】useEffect 和上下文 api【英文标题】:useEffect and the context api 【发布时间】:2020-08-19 14:57:51 【问题描述】:

我遇到了一个奇怪的问题,useEffect 没有注意到上下文 api 正在改变的值的变化。我有一个每次更改某个值时都想运行的提取,并且我正在使用上下文 api 来管理我的状态值,但它似乎从来没有注意到。当我传递道具而不是使用上下文 api 时,我没有遇到这个问题。我没有使用这个技巧吗?控制台错误是:./src/Components/CustomTrip.js 第 33:12 行:React Hook useEffect 缺少依赖项:'fetchDistance'。要么包含它,要么移除依赖数组 react-hooks/exhaustive-deps

import React, useContext, useEffect  from 'react'
import  COORDS  from "./coords"
import  MileContext  from './MileContext';
import useCalculateTotals from "./CalculateTotals";

    const CustomTrip = () => 
      const locationOne, locationTwo, setLocationOne, setLocationTwo, setTotalMiles  = useContext(MileContext);

      const onLocationOneChange = (event) => 
        setLocationOne(event.target.value)
      
      const onLocationTwoChange = (event) => 
        setLocationTwo(event.target.value)
      
      const onTotalMileChange = (value) => 
        setTotalMiles(value)    
      ;
      useCalculateTotals();

      async function fetchDistance()
            
                const res = await fetch("https://api.mapbox.com/directions-matrix/v1/mapbox/driving/" + locationOne + ";" + locationTwo + "?sources=1&annotations=distance&access_token=pk.eyJ1Ijoiam9zaGlzcGx1dGFyIiwiYSI6ImNqeTZwNGF1ODAxa2IzZHA2Zm9iOWNhNXYifQ.X0D2p9KD-IXd7keb199nbg")
                const mapBoxObject = await res.json();
                const meters = mapBoxObject.distances[0];
                const miles = parseInt(meters) *  0.00062137119;
                console.log(miles.toFixed(2));
                onTotalMileChange(miles.toFixed(2));  
                console.log(miles);
                     

        useEffect(() => 
            fetchDistance()
        , [locationOne, locationTwo]);

      return (
        <div>
          <h3>Customize your trip</h3>
            Mileage will be calculated as a round trip.
            <br/>
            Select your starting point
            <select value=locationOne onChange=onLocationOneChange>
            
                Object.entries(COORDS).map(([campus, coordinates]) => (
                <option key=campus value=coordinates>
                campus
                </option>
            ))
            </select>
            Select your destination
            <select value=locationTwo onChange=onLocationTwoChange>
            
                Object.entries(COORDS).map(([campus, coordinates]) => (
                <option key=campus value=coordinates>
                campus
                </option>
            ))
            </select>
        </div>
      )
    ;

export default CustomTrip;

这里是更多 umm 上下文的 api 上下文。

import React,useState, createContext from 'react';

export const MileContext = createContext();

export const MileProvider = props => 
    const [totalMiles, setTotalMiles] = useState(0);
    const [drivers, setDrivers] = useState(1);
    const [rentalPaddingDay, setRentalPaddingDay] = useState(1);
    const [hotelCost, setHotelCost] = useState(0);
    const [hotelDays, setHotelDays] = useState(0);
    const [hotelTotal, setHotelTotal] = useState(0);
    const [drivingDays, setDrivingDays] = useState(0);
    const [hotelNights, setHotelNights] = useState(0);
    const [hours, setHours] = useState(0);
    const [meals, setMeals] = useState(0);
    const [laborCost, setLaborCost] = useState(0);
    const [truck26Total, setTruck26Total] = useState(0);
    const [truck16Total, setTruck16Total] = useState(0);
    const [vanTotal, setVanTotal] = useState(0);
    const [mealCost, setMealCost] = useState(0);
    const [vanFuelCost, setVanFuelCost] = useState(0);
    const [rental26Cost, setRental26Cost] = useState(0);
    const [rental16Cost, setRental16Cost] = useState(0);
    const [truck26Fuel, setTruck26Fuel] = useState(0);
    const [truck16Fuel, setTruck16Fuel] = useState(0);
    const [trip, setTrip] = useState("Custom");
    const [locationOne, setLocationOne] = useState("-97.4111604,35.4653761");
    const [locationTwo, setLocationTwo] = useState("-73.778716,42.740913");
    const [gas, setGas] = useState(2.465);
    const [diesel, setDiesel] = useState(2.91);

    return (
        <MileContext.Provider 
        value = 
            totalMiles, 
            setTotalMiles, 
            drivers, 
            setDrivers,
            rentalPaddingDay,
            setRentalPaddingDay,
            hotelCost,
            setHotelCost,
            hotelDays,
            setHotelDays,
            hotelTotal,
            setHotelTotal,
            drivingDays,
            setDrivingDays,
            drivers,
            setDrivers,
            hotelNights,
            setHotelNights,
            hours,
            setHours,
            meals,
            setMeals,
            laborCost,
            setLaborCost,
            truck26Total,
            setTruck26Total,
            truck16Total,
            setTruck16Total,
            vanTotal,
            setVanTotal,
            mealCost,
            setMealCost,
            vanFuelCost,
            setVanFuelCost,
            rental26Cost,
            setRental26Cost,
            rental16Cost,
            setRental16Cost,
            truck26Fuel,
            setTruck26Fuel,
            truck16Fuel,
            setTruck16Fuel,
            trip,
            setTrip,
            locationOne,
            setLocationOne,
            locationTwo,
            setLocationTwo,
            gas,
            setGas,
            diesel,
            setDiesel
        >
            props.children    
        </MileContext.Provider>
    )

【问题讨论】:

您如何更新MileContext 提供程序上的值? 我在每个组件中使用 changehandlers 来更改 MileContext 中的值,然后在 MileContext 我使用 useState。 locationOne 和 locationTwo 正在更改状态值,但 useEffect 在它们更改时不会触发。 您需要包含一个更新上下文值的示例。我怀疑您可能只是更改了同一上下文实例上的 locationOnelocationTwo 值,而没有使用更新的值设置全新的上下文实例,从而阻止 React 检测到更改的值。 @Sly_cardinal 我认为你可能是对的。我已经更新了最初的问题。 【参考方案1】:

除了另一个文件中的拼写错误之外,代码没有问题。经过进一步审查,我发现导入的 COORDS 对象中有空格,当放置在 api 调用的 url 中时,这些空格被转换为 %20。删除空格立即解决了问题。

【讨论】:

【参考方案2】:

使用它,它会起作用的

    const contextObj = useContext(MileContext);

    useEffect(() => 
        fetchDistance()
    , [...Object.values(contextObj)]);

【讨论】:

这让情况变得更糟。现在我有“未处理的拒绝(TypeError):无法读取未定义的属性'0'” 我已经更新了我的解决方案,你可以试试。 这是一个如此原始的字符串

以上是关于useEffect 和上下文 api的主要内容,如果未能解决你的问题,请参考以下文章

React/React Context API:使用 useEffect() 钩子时等待上下文值

React 中带有 useEffect 的异步上下文

如何使用 useEffect 和 Context API 来检查用户是不是登录并保护路由?

React:使用 Refs 修复缺少的依赖警告 useEffect

如何在useEffect中使用上下文值,只运行一次

使用 useEffect 在页面加载时从上下文中获取数据