【问题标题】:React, unexpected multiple result when using map and fetch使用 map 和 fetch 时反应,意外的多个结果
【发布时间】:2021-07-21 19:27:44
【问题描述】:

我正在构建天气应用程序,我的想法是将城市名称保存在 localStorage 中,将道具传递给子组件,然后使用地图进行迭代并在第一个子组件的单独子组件中显示每个子组件

问题是渲染时显示的数据加倍/三倍(取决于渲染发生时的组件)所以当我有例如伦敦市并添加柏林市时,它将渲染:

伦敦,伦敦,柏林

问题不在于 AddCity 组件,它工作正常,但在这种异步 setState/fetching 和映射的混合中

请看下面的代码

应用(父组件)

const App = () => {


const [cities, setCities] = useState([]);


const addCity = (newCity)=>{
    console.log('adding')
    setCities([...cities, newCity]);
    let cityId = localStorage.length;
     localStorage.setItem(`city${cityId}`, newCity);
 
}



useEffect(() => {
     loadCityFromLocalStore()
 
}, [])



const loadCityFromLocalStore =()=>{   
    setCities([...cities, ...Object.values(localStorage)])
}


return (
    
    <div>
        <Header />
        <AddCity addCity={addCity}/>
        <DisplayWeather displayWeather={cities}/>
    </div>
)

}

DisplayWeather(第一个孩子)

 const DisplayWeather = ({displayWeather}) => {


const apiKey = '4c97ef52cb86a6fa1cff027ac4a37671';
const [fetchData, setFetchData] = useState([]);


useEffect(() => {

    displayWeather.map(async city=>{
        const res =await fetch(`http://api.openweathermap.org/data/2.5/weather?q=${city}&units=metric&appid=${apiKey}`)
        const data = await res.json();

            setFetchData((fetchData=>[...fetchData , data]));                         
    })
    

}, [displayWeather])


return (
    <>
        {fetchData.map(data=>(            
             <ul>
                 <Weather                             
                    data={data}/> 
              </ul>
        ))}
    </>
)

}

天气组件

    const Weather = ({data}) => {

return (
    <li>       
        {data.name}
    </li>
)

}

【问题讨论】:

    标签: reactjs dictionary fetch


    【解决方案1】:

    问题似乎来自于为您之前添加的城市调用setFetchData

    解决此问题的一种简单方法是将获取数据存储为对象而不是字典,这样您只需覆盖该城市的数据以防它已经存在(或者甚至可以跳过获取,因为您已经拥有数据)。

    例如:

    const [fetchData, setFetchData] = useState({});
    
    useEffect(() => {
    
        displayWeather.map(async city=>{
            const res = await fetch(`http://api.openweathermap.org/data/2.5/weather?q=${city}&units=metric&appid=${apiKey}`)
            const data = await res.json();
    
            setFetchData((fetchData=> ({...fetchData, [city]: data})));                        
        })
        
    
    }, [displayWeather])
    
    

    然后,要映射获取数据,您可以使用 Object.values:

    return (
        <>
            {Object.values(fetchData).map(data=>(            
                 <ul>
                     <Weather                             
                        data={data}/> 
                  </ul>
            ))}
        </>
    )
    
    

    如果你想跳过已经获取的城市,你可以这样做:

    useEffect(() => {
    
        displayWeather.map(async city=>{
            if (!fetchData[city]) {
                const res = await  fetch(`http://api.openweathermap.org/data/2.5/weather?q=${city}&units=metric&appid=${apiKey}`)
                const data = await res.json();
    
                setFetchData((fetchData=> ({...fetchData, [city]: data})));
            }
        })
    

    【讨论】:

    • 谢谢这是一个很好的解决方案我想知道这个应用程序的结构/架构是否正确(这种解决方法是标准情况)或者我可以用其他方式构建它以避免第一名
    • 我看不出这个架构有什么问题。另一个具有不同优点和缺点的潜在架构可能是删除中间DisplayWeather 组件,将city.map 移动到父级,并在Weather 组件内进行获取。不过,您将不得不处理天气组件中从一开始就不可用的数据。我可能会在这些方面做更多的事情,但我认为这两种方法都很好。
    • 根据我的经验,从对象移动到数组,反之亦然。我不一定将其称为解决方法,更改数据结构以适应您的约束是数据结构的意义所在。此外,应该保持同步的数组很容易出错,我倾向于使用对象。
    猜你喜欢
    • 2019-10-19
    • 2021-06-06
    • 2019-05-05
    • 2017-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-24
    • 2018-10-03
    相关资源
    最近更新 更多