JS/React如果不存在URL,如何防止数据获取数据?
我正在编写一个基于用户操作的API数据的应用程序。
我有问题,因为我有一个搜索栏,可以改变状态的价值。然后,我在此链接中使用该状态代替 $ {search}
var baseurl =`https://www.alphavantage.co/query/query?function= time_series_series_series_daily&symbol搜索}& apikey = demo`;
使用该链接i然后基于用户的输入获取数据,该输入存储在搜索/setSearch状态中。
但是,应用程序完全崩溃了。因为应用程序开始拉数据从API到每当状态发生变化。用户输入,
因此可以:
`alphavantage.co/query?function=TIME_SERIES_DAILY&symbol=M&apikey=demo`; // M
`alphavantage.co/query?function=TIME_SERIES_DAILY&symbol=MS&apikey=demo`; // MS
`alphavantage.co/query?function=TIME_SERIES_DAILY&symbol=MSF&apikey=demo`; // MSF
`alphavantage.co/query?function=TIME_SERIES_DAILY&symbol=MSFT&apikey=demo`; // MSFT
尝试获取搜索栏中每个字母的数据
,如果链接不存在,则应用程序将崩溃(这是 问题! )
,给我一个错误的话! 未定义或无效转换为对象”。
“不能将 崩溃,只有在链接正确的情况下才获取数据。.我尝试使用lodash.debounce(类似Settimeout)等待几秒钟以允许用户完成库存的全名。但是,如果用户擦除了搜索,然后该应用程序试图获取一个空字符串
https://www.alphavantage.co/query?function=Time_Series_series_daily&Amp;
(在符号=之后,它没有通过,没有这样的链接,因此应用程序未能获取正确的数据后崩溃)
我认为这可能会通过有条件的渲染来解决 - 我试图有条件地渲染数据(如果图表==未定义,则...)..但是,如果链接错误 - 该应用程序一如既往地崩溃,无论其是否有条件地渲染!
仅供参考,这是我在渲染搜索栏的组件//
const StockSearchBar = () => {
const { search, setSearch } = useContext(SearchContext); // state is stored in context API in another file
function handleButtonEvents(e) {
handleClick();
setTimeout(() => window.location.reload(), 3000);
}
const handleSearch = (e) => { // searchbar functionality
e.preventDefault();
setSearch(e.target.value.toUpperCase());
debounce(() => setSearch(e.target.value.toUpperCase()), 2000); // debounce 2000 milliseconds
// setTimeout(() => setSearch(e.target.value.toUpperCase()), 2500);
};
const handleClick = (e) => { // this is for backend - ignore it
if (setSearch !== '') {
const options =
{
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({search}),
};
const response = fetch(`http://localhost:3001/api/search`, options);
console.log("search entered");
console.log(response)
};
}
return (
<>
<div className="searchBar">
<label>Look for Stocks or Cryptos: </label>
// this is the searchbar
<input type='text' onChange={handleSearch} onKeyPress={(ev) => {
if (ev.key === "Enter") {
handleButtonEvents();
}}}
placeholder={search} required/>
<Button variant="success" type="submit" onClick={handleButtonEvents} >Search</Button>
</div>
<h1 className="src">{search}</h1>
</>
);
};
export default StockSearchBar;
基本上,我需要找出一种方法,以防止数据获取,如果链接(基于状态)不是正确的链接。或至少这就是我认为我的问题。
import { createContext, useEffect, useState } from "react";
const SearchContext = createContext();
export function SearchProvider({ children }) {
const [search, setSearch] = useState("AAPL")
return (
<SearchContext.Provider value={{ search, setSearch }}>{children}</SearchContext.Provider>
)
}
export default SearchContext;
^这是我的上下文API文件 - 在该应用程序中存储和共享状态的
一个解决方案,我认为可能会有所帮助是使用OnSubmit或OnClick切换Onchange,然后将状态保存到LocalStorage(因为OnClick/OnSubmit会刷新整个页面,包括状态。我尝试了e.preventdefault 。
。演示链接到API供公共使用
编辑//更新 好的,所以我让该应用程序可以使用if(搜索栏为空,然后设置状态) - 多亏了Robert的评论。.
const handleSearch = (e) => {
e.preventDefault();
if (e.target.value !== ``) {
setSearch(e.target.value.toUpperCase())
}
};
我尚未添加此文件(组件),但是我认为将其包括在内很重要明显的原因是错误来自这里
function LineChart(props) {
const { search, setSearch } = useContext(SearchContext);
var baseUrl = `https://www.alphavantage.co/query?function=TIME_SERIES_DAILY&symbol=${search}&apikey=demo`;
const [chart, setChart] = useState();
useEffect(() => { // fetching data from api
axios.get(baseUrl)
.then(res => {
setChart(res.data);
})
}, [baseUrl]);
useEffect(()=>{}, [chart]);
const stockPrices = useMemo(() => chart && Object.values(chart['Time Series (Daily)']).map(i => i['1. open']).reverse(), [chart]); // store stock prices in stockPrices
const stockDates = useMemo(() => chart && Object.keys(chart['Time Series (Daily)']).map(x => x.replace(/\d{4}-/, "")).reverse(), [chart]); // store dates in stockDates
// display stock chart + settings using chart.js
var data = {
labels: stockDates,
datasets: [{
label: `${search}`,
data: stockPrices,
backgroundColor: "rgba(255,116,89,0.05)",
borderColor: "rgba(255,105,75,1)",
borderWidth: 2,
pointBorderColor: "#2984c5",
pointBackgroundColor: "#fff",
pointHoverRadius: 5,
pointHoverBackgroundColor: 'black',
fill: true,
pointHoverBorderColor: "rgba(41, 132, 197, 1)",
pointHoverBorderWidth: 7,
pointRadius: 0,
pointHitRadius: 30,
tension: 0.3,
}]
};
var options = {
plugins: {
legend: {
display: '',
labels: {
color: 'white',
font: {
size: 30,
family: 'verdana',
},
}
}
},
maintainAspectRatio: true,
responsive: false,
radius: 3,
scales: {
y: {
ticks: {
callback: function (value) {
return "$" + value;
},
color: 'rgba(210,230,244,1)',
font: {
size: 12,
family: "Verdana" // Add your font here to change the font of your legend label
}
},
grid: {
color: 'rgba(255,255,255,0.02)',
}
},
x: {
grid: {
color: 'rgba(255,255,255,0.02)',
},
ticks: {
color: 'rgba(210,230,244,1)',
font: {
family: "Verdana" // Add your font here to change the font of your legend label
}
}
},
},
}
return (
<>
<div className='chartcont'>
<Line data={data} height={800} width={1200} options={options} /> {/* DISPLAY CHART BASED ON THE FETCHED DATA */}
</div>
<button onClick={() => setSearch("NIO")}>CLICK ME</button>
<h1 className='src'>{search}</h1> {/* ADDED THIS FOR TESTING PURPOSES */}
</>
);
}
export default LineChart;
I'm writing an APP that fetches data from an API - based on user's actions.
I have a problem, because I have a search bar that changes the value of state. Then I use that state in the place of ${search} in this link
var baseUrl = `https://www.alphavantage.co/query?function=TIME_SERIES_DAILY&symbol=${search}&apikey=demo`;
using that link I then fetch data based on user's input which is stored in search/setSearch state..
However the app completely crashes quite often.. because the app starts to pull data from the API whenever state changes.. for example if user wants to check data for "MSFT" ( Microsoft company ), and starts typing M-S-F-T.. the app will crash as it's trying to fetch data for every single letter that the user enters
so it goes to:
`alphavantage.co/query?function=TIME_SERIES_DAILY&symbol=M&apikey=demo`; // M
`alphavantage.co/query?function=TIME_SERIES_DAILY&symbol=MS&apikey=demo`; // MS
`alphavantage.co/query?function=TIME_SERIES_DAILY&symbol=MSF&apikey=demo`; // MSF
`alphavantage.co/query?function=TIME_SERIES_DAILY&symbol=MSFT&apikey=demo`; // MSFT
and tries to fetch data for every letter entered in the search bar
If the link doesn't exist, the app will crash ( this is the PROBLEM! )
and give me an error saying! "Cannot convert undefined or null to object" - of couse.. the link doesnt exist so its undefined/null as there's nothing to get
Anyways, I need to find a way to handle the app in a way that at least it doesn't crash, and only fetches data if the link is correct.. I tried to use lodash.debounce ( something like setTimeout ) to wait a few seconds to allow the user to finish writing a full name of the stock.. however if the user erases the search, then the app tries to fetch data for an empty string
https://www.alphavantage.co/query?function=TIME_SERIES_DAILY&symbol=&apikey=demo
;
(after symbol= it passes nothing, there's no such link so the app crashes after failing to fetch proper data )
I thought this could potentially be fixed with conditional rendering - and I tried to render the data conditionally (if chart == undefined then ... ).. but if the link is wrong - the app crashes as always, whether its rendered conditionally or not!
Just for reference, here's the component in which I'm rendering the search bar //
const StockSearchBar = () => {
const { search, setSearch } = useContext(SearchContext); // state is stored in context API in another file
function handleButtonEvents(e) {
handleClick();
setTimeout(() => window.location.reload(), 3000);
}
const handleSearch = (e) => { // searchbar functionality
e.preventDefault();
setSearch(e.target.value.toUpperCase());
debounce(() => setSearch(e.target.value.toUpperCase()), 2000); // debounce 2000 milliseconds
// setTimeout(() => setSearch(e.target.value.toUpperCase()), 2500);
};
const handleClick = (e) => { // this is for backend - ignore it
if (setSearch !== '') {
const options =
{
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({search}),
};
const response = fetch(`http://localhost:3001/api/search`, options);
console.log("search entered");
console.log(response)
};
}
return (
<>
<div className="searchBar">
<label>Look for Stocks or Cryptos: </label>
// this is the searchbar
<input type='text' onChange={handleSearch} onKeyPress={(ev) => {
if (ev.key === "Enter") {
handleButtonEvents();
}}}
placeholder={search} required/>
<Button variant="success" type="submit" onClick={handleButtonEvents} >Search</Button>
</div>
<h1 className="src">{search}</h1>
</>
);
};
export default StockSearchBar;
Basically, I need to figure out a way to prevent data from being fetched if the link (based on state) isn't a proper link. Or at least that's what I think my problem is.
import { createContext, useEffect, useState } from "react";
const SearchContext = createContext();
export function SearchProvider({ children }) {
const [search, setSearch] = useState("AAPL")
return (
<SearchContext.Provider value={{ search, setSearch }}>{children}</SearchContext.Provider>
)
}
export default SearchContext;
^ This is my context api file - it's where state is stored and shared across the app
One solution I think could possibly help is switching onChange with onSubmit or onClick and then saving state to localStorage ( because onClick/onSubmit refreshes the whole page including state.. I tried e.preventDefault but for some reason it refuses to work in the browser giving me an error that "preventDefault(); is not a function"...) however, I'm still trying to figure out how to do it.. but logically it makes sense
https://www.alphavantage.co/query?function=TIME_SERIES_DAILY&symbol=MSFT&apikey=demo --> demo link to the API for public use
EDIT // UPDATE
ok, so I got the app to work a lot better with an if (searchbar is empty then dont set state) - thanks to Robert's comment..
const handleSearch = (e) => {
e.preventDefault();
if (e.target.value !== ``) {
setSearch(e.target.value.toUpperCase())
}
};
I have not added this file (component), however I think it's important to include it for obvious reasons as the error is coming from here
function LineChart(props) {
const { search, setSearch } = useContext(SearchContext);
var baseUrl = `https://www.alphavantage.co/query?function=TIME_SERIES_DAILY&symbol=${search}&apikey=demo`;
const [chart, setChart] = useState();
useEffect(() => { // fetching data from api
axios.get(baseUrl)
.then(res => {
setChart(res.data);
})
}, [baseUrl]);
useEffect(()=>{}, [chart]);
const stockPrices = useMemo(() => chart && Object.values(chart['Time Series (Daily)']).map(i => i['1. open']).reverse(), [chart]); // store stock prices in stockPrices
const stockDates = useMemo(() => chart && Object.keys(chart['Time Series (Daily)']).map(x => x.replace(/\d{4}-/, "")).reverse(), [chart]); // store dates in stockDates
// display stock chart + settings using chart.js
var data = {
labels: stockDates,
datasets: [{
label: `${search}`,
data: stockPrices,
backgroundColor: "rgba(255,116,89,0.05)",
borderColor: "rgba(255,105,75,1)",
borderWidth: 2,
pointBorderColor: "#2984c5",
pointBackgroundColor: "#fff",
pointHoverRadius: 5,
pointHoverBackgroundColor: 'black',
fill: true,
pointHoverBorderColor: "rgba(41, 132, 197, 1)",
pointHoverBorderWidth: 7,
pointRadius: 0,
pointHitRadius: 30,
tension: 0.3,
}]
};
var options = {
plugins: {
legend: {
display: '',
labels: {
color: 'white',
font: {
size: 30,
family: 'verdana',
},
}
}
},
maintainAspectRatio: true,
responsive: false,
radius: 3,
scales: {
y: {
ticks: {
callback: function (value) {
return "quot; + value;
},
color: 'rgba(210,230,244,1)',
font: {
size: 12,
family: "Verdana" // Add your font here to change the font of your legend label
}
},
grid: {
color: 'rgba(255,255,255,0.02)',
}
},
x: {
grid: {
color: 'rgba(255,255,255,0.02)',
},
ticks: {
color: 'rgba(210,230,244,1)',
font: {
family: "Verdana" // Add your font here to change the font of your legend label
}
}
},
},
}
return (
<>
<div className='chartcont'>
<Line data={data} height={800} width={1200} options={options} /> {/* DISPLAY CHART BASED ON THE FETCHED DATA */}
</div>
<button onClick={() => setSearch("NIO")}>CLICK ME</button>
<h1 className='src'>{search}</h1> {/* ADDED THIS FOR TESTING PURPOSES */}
</>
);
}
export default LineChart;
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
有两种类型的错误可能会破坏提取请求,要么不存在链接,要么存在链接,但没有读取数据。错误键入块可用于记录错误而不会崩溃程序。我已经使用以下结构从时不时地从几千个生成的链接中获取,其中一个链接之一是不好的,或者不存在JSON数据。它阻止了崩溃,并默默地报告了安机。
There are two types of error that might defeat a fetch request, either the link doesn't exist, or a link exists but doesn't have data to be read. A error-catch block can be used to log the error without crashing the programme. I have used the following structure to fetch from a few thousand generated links where every now and then, one of the links is bad or the json data not present. It prevented crashes and reported silently to console.