我有一个基于API的React天气项目 我有一个名为 CHART 的组件,但它没有更新项目最重要的部分。 每当我输入城市名称时,它都会获取所有信息并更新项目的书面部分。但它不是用图表来做的。它总是显示第一次调用的第一个值但不更新。 当我进入 Chart.js 文件并在项目中留出一个空间并点击“保存”时,它会显示基于 API 的正确图表。 我可以闻到一定有 useEffect Hook 的用例,但是如何?
这是子组件
import React, { useEffect, useState } from 'react';
import { Line } from 'react-chartjs-2';
import { Chart as ChartJS} from 'chart.js/auto';
const Chart = ({following}) => {
const date = following.map(item => new Date(item.dt * 1000));
const dateLocal = date.map(item => item.toLocaleString('default', { weekday: 'long' }));
const temp = following.map(item => Math.floor(item.temp.day));
const [userData, setUserData] = useState({
labels: dateLocal,
datasets: [
{
data: temp,
label: 'Temperature',
backgroundColor: [
'rgba(0, 0, 0,.5)',
'rgba(0, 0, 0,.5)',
'rgba(0, 0, 0,.5)',
],
color : ['rgba(0,0,0,1)'],
fill:true,
pointRadius: 1,
pointHitRadius:4,
pointHoverRadius:8,
pointBackgroundColor: 'mediumblue',
borderWidth: 2,
pointBorderColor: 'lightblue',
pointBorderWidth: 2,
pointHoverBorderWidth: 2,
tooltips: {
mode: 'index',
intersect: true,
windowPadding: 10,
},
scales: {
xAxes: [{
gridLines: {
display: false,
},
ticks: {
fontColor: 'green',
zeroLineColor: 'blue',
callback :
function (value) {
return value
}
}
}],
yAxes: [{
gridLines: {
display: false,
},
ticks: {
fontColor: 'black',
fontSize: 112,
fontStyle: 'bold',
color: 'red',
callback :
function (value) {
return value
}
}
}]
}
}
]
});
return (
<div className="line" style={{ width:'100%'}}>
<Line
data={userData}
/>
</div>
)
};
export default Chart;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
这是父App.js
import React, { useEffect, useState } from 'react';
import Chart from './Chart';
const api = {
key: `${process.env.REACT_APP_API_KEY}`,
base: 'https://api.openweathermap.org/data/2.5/'
}
function App() {
const [query, setQuery] = useState('');
const [weather, setWeather] = useState({});
const [location, setLocation] = useState({ lat: '', lon: '' });
const [following, setFollowing] = useState([]);
const search = async (e) => {
if (e.key === 'Enter') {
await fetch(`${api.base}weather?q=${query}&units=metric&appid=${api.key}&lang=tr`)
.then(res => res.json())
.then(result => {
setWeather(result);
setQuery('');
setLocation(result.coord);
console.log(result);
searchFollowing();
}
)
}
}
useEffect(() => {
if (location.lat && location.lon) {
searchFollowing();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [location])
const searchFollowing = async () => {
await fetch(`${api.base}onecall?lat=${location.lat}&lon=${location.lon}&units=metric&exclude=hourly,minutely&appid=${api.key}`)
.then(res => res.json())
.then(result2 => {
const array = result2.daily.slice(1, 6);
console.log(following);
setFollowing(array);
// following == array
}
)
}
const integer = (number) => {
return Math.floor(Math.round(number));
}
const mapped = (following) => {
following = [...following];
return following.map((item, idx) => {
const date = new Date(item.dt * 1000);
const date1 = date.toLocaleString('default', { weekday: 'long' });
const icon = item.weather[0].icon;
const day = integer(item.temp.day);
const night = integer(item.temp.night);
return (
<div key={idx} className="box">
<h4>{date1}</h4>
<img
src={`http://openweathermap.org/img/wn/${icon}.png`}
alt='weather'
width={100}
height={100}
/>
<h4>Gündüz {day} °C</h4>
<h4>Gece {night} °C</h4>
</div>
)
})
}
const dateBuild = (d) => {
let months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
let days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']
let day = days[d.getDay()]
let date = d.getDate()
let month = months[d.getMonth()]
let year = d.getFullYear()
return `${day} ${date} ${month} ${year}`
}
return (
<div className={(typeof weather.main !== 'undefined') ?
((weather.main.temp > 25) ? 'App hot' :
((weather.main.temp < 25 && weather.main.temp > 5) ?
'App warm' : 'App')) : 'App'}>
<main>
<div className="search-box">
<input
type="text"
className="search-bar"
placeholder="Search for a location..."
onChange={e => setQuery(e.target.value)}
onKeyPress={search}
value={query}
/>
</div>
{(typeof weather.main != "undefined") ? (
<div className="content">
<div className="location-box">
<div className="location">
{weather.name}, {weather.sys.country}
</div>
<div className="date"> {dateBuild(new Date())}
</div>
</div>
<div className="weather-box">
<div className="temp">
{Math.round(weather.main.temp)}°C
<img
src={`http://openweathermap.org/img/wn/${weather.weather[0].icon.slice(0, 2)}d.png`}
alt='weather'
width={150}
height={150}
/>
</div>
<div className="weather">
<p>
<span>Hissedilen</span>
{Math.floor(weather.main.feels_like)} °C
</p>
<p>
<span>Şu an</span>
{weather.weather[0].description}
</p>
<p>
<span>Basınç</span>
{weather.main.pressure} mb
</p>
<p>
<span>Rüzgar </span>
{Math.floor(weather.wind.speed)} km/h
</p>
<p>
<span>En fazla</span>
{Math.floor(weather.main.temp_max)} °C
</p>
<p>
<span>En az</span>
{Math.floor(weather.main.temp_min)} °C
</p>
</div>
</div>
<Chart following={following} />
<div className="followingdays"
>
{mapped(following)}
</div>
</div>) : ('')}
</main>
</div>
);
}
export default App;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
UPDATE1 ==> 我用 useEffect 钩子完成了它,无法使用内置方法 update() 完成它
import React, { useEffect, useState } from 'react';
import { Line } from 'react-chartjs-2';
import { Chart as ChartJS} from 'chart.js/auto';
const Chart = ({following}) => {
const date = following.map(item => new Date(item.dt * 1000));
const dateLocal = date.map(item => item.toLocaleString('default', { weekday: 'long' }));
const temp = following.map(item => Math.floor(item.temp.day));
// if userData changes then the chart will re-render
useEffect(() => {
setUserData({
labels: dateLocal,
datasets: [
{
data: temp,
label: 'Temperature',
backgroundColor: [
'rgba(0, 0, 0,.5)',
'rgba(0, 0, 0,.5)',
'rgba(0, 0, 0,.5)',
],
color : ['rgba(0,0,0,1)'],
fill:true,
pointRadius: 1,
pointHitRadius:4,
pointHoverRadius:8,
pointBackgroundColor: 'mediumblue',
borderWidth: 2,
pointBorderColor: 'lightblue',
pointBorderWidth: 2,
pointHoverBorderWidth: 2,
tooltips: {
mode: 'index',
intersect: true,
windowPadding: 10,
},
scales: {
xAxes: [{
gridLines: {
display: false,
},
ticks: {
fontColor: 'green'
}
}],
yAxes: [{
gridLines: {
display: false,
},
ticks: {
fontColor: 'green'
}
}]
}
}
]
});
},[following]);
const [userData, setUserData] = useState({
labels: dateLocal,
datasets: [
{
data: temp,
label: 'Temperature',
backgroundColor: [
'rgba(0, 0, 0,.5)',
'rgba(0, 0, 0,.5)',
'rgba(0, 0, 0,.5)',
],
color : ['rgba(0,0,0,1)'],
fill:true,
pointRadius: 1,
pointHitRadius:4,
pointHoverRadius:8,
pointBackgroundColor: 'mediumblue',
borderWidth: 2,
pointBorderColor: 'lightblue',
pointBorderWidth: 2,
pointHoverBorderWidth: 2,
tooltips: {
mode: 'index',
intersect: true,
windowPadding: 10,
},
scales: {
xAxes: [{
gridLines: {
display: false,
},
ticks: {
fontColor: 'green'
}
}],
yAxes: [{
gridLines: {
display: false,
},
ticks: {
fontColor: 'green'
}
}]
}
}
]
});
return (
<div className="line" style={{ width:'100%'}}>
<Line className="actual-chart"
data={userData}
redraw={true}
/>
</div>
)
};
export default Chart;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Chart.js 有 update 方法。尝试将图表保存在变量中,然后在必要时调用 foo.update()
我通过添加随机数作为图表元素的键来修复我的问题。示例;
<div>
<Line
key={Math.random()}
data={userData}
/>
</div>