React应用添加特定函数时出现Cannot set properties of null错误求助
问题
我在React应用里写了一段调用API的代码,输入国家名称返回对应首都。为了输出大小写规范的国名,额外加了个从API获取标准国名的函数。但只要保留这段获取国名的代码,绝大多数情况下会报错;删掉就完全正常。偶尔微调代码能暂时好,但刷新网页问题又回来。控制台明明能看到两个输出结果,还是报错。
代码如下:
function SearchButton() { async function GetCountryName(countryInput) { //Gets correctly capitalised country name const response = await fetch(`https://restcountries.com/v3.1/name/${countryInput}?fields=name`); const text = await response.text(); let countryOutput = text.split('\",\"')[0]; //Removes superfluous characters after name countryOutput = countryOutput.split('\":\"')[1]; //Removes superfluous characters before name console.log(countryOutput); return countryOutput; } const displayResult = document.getElementById("output"); //Gets output location async function handleClick() { //Searches in API for the country in the textbox const countryInput = document.getElementById("Country").value.toLowerCase(); //Gets input if (countryInput){ const response = await fetch(`https://restcountries.com/v3.1/name/${countryInput}?fields=capital`); //Finds capital const text = await response.text(); const countryOutput = await GetCountryName(countryInput); if (!text.includes("capital")) { //If there is not a valid output for the input displayResult.innerHTML = `Please enter a country.`; } else { const textOut = text.split('\"]')[0]; //Removes superfluous characters after capital const textFinal = textOut.split('[\"')[1]; //Removes superfluous characters before capital console.log(countryOutput); console.log(textFinal); displayResult.innerHTML = `The capital of ${countryOutput} is ${textFinal}`; } } else { //If clicked without search term displayResult.innerHTML = `Please enter a country.`; } } return ( <button type="button" id="SearchButton" onClick={handleClick}> Search </button>); }
解决方案
问题根源
- 违反React数据驱动原则,直接操作DOM:组件初始化时就用
document.getElementById获取DOM元素,但React组件会频繁重渲染,这个引用随时可能失效,后续修改innerHTML时必然报错。 - 字符串分割解析JSON极其脆弱:API返回的JSON格式稍有变化(比如字段顺序、多了空格),分割就会失败,拿到
undefined,插入页面时触发错误。 - 无请求错误处理:网络超时、API返回错误码时,
fetch不会主动抛错,后续处理错误文本时必然出问题。
修复后的代码
import { useState } from 'react'; function SearchButton() { // 用React状态管理结果,不再直接操作DOM const [result, setResult] = useState(''); async function getCountryName(countryInput) { try { const response = await fetch(`https://restcountries.com/v3.1/name/${countryInput}?fields=name`); // 检查请求是否成功 if (!response.ok) throw new Error('国名请求失败'); // 直接解析JSON,不用字符串分割 const data = await response.json(); // 优先取官方名称,没有就取通用名称 return data[0]?.name?.official || data[0]?.name?.common; } catch (err) { console.error('获取国名出错:', err); return null; } } async function handleClick() { const countryInput = document.getElementById("Country").value.trim().toLowerCase(); if (!countryInput) { setResult('Please enter a country.'); return; } try { // 并行发起两个请求,减少等待时间 const [capitalRes, countryName] = await Promise.all([ fetch(`https://restcountries.com/v3.1/name/${countryInput}?fields=capital`), getCountryName(countryInput) ]); if (!capitalRes.ok) throw new Error('首都信息请求失败'); const capitalData = await capitalRes.json(); // 用可选链避免数据不存在时报错 const capital = capitalData[0]?.capital?.[0]; if (!capital || !countryName) { setResult('Please enter a country.'); return; } // 用状态更新页面内容 setResult(`The capital of ${countryName} is ${capital}`); } catch (err) { console.error('搜索出错:', err); setResult('Please enter a country.'); } } return ( <> <button type="button" id="SearchButton" onClick={handleClick}> Search </button> {/* 用React状态渲染结果 */} <div id="output">{result}</div> </> ); }
关键修复点
- 改用React的
useState管理结果状态,完全遵循数据驱动视图的规则,彻底避免DOM操作带来的问题。 - 用
response.json()解析API响应,直接从对象中提取字段,再也不用担心JSON格式小变化导致的解析失败。 - 加入
try/catch处理网络请求错误,任何环节出错都会被捕获,不会导致程序崩溃。 - 用
Promise.all并行发起两个API请求,提升搜索速度。 - 用可选链
?.处理可能不存在的字段,避免因API返回数据结构变化抛出错误。
内容的提问来源于stack exchange,提问作者Jacob
相关产品推荐
相关产品推荐

