React按钮触发searchSpell报request非函数错误解决方法
问题描述
我在开发自己的第一个React项目,想要实现点击按钮触发searchSpell函数的功能,但按钮点击后始终无法正常运行,控制台持续抛出如下错误:
Uncaught TypeError: axios_api_js__WEBPACK_IMPORTED_MODULE_1_.default.request is not a function
相关代码如下:
Header组件代码
const { searchSpell } = Hooker(); const [whatSpell, setWhatSpell] = useState() function pesquisar () { if(!whatSpell){ alert("escreva alguma coisa antes de pesquisar") return } else{ return searchSpell(whatSpell) } }
自定义Hook代码
import { SpellContext } from "../provider.js" function Hooker (){ const { spellState, searchSpell } = useContext(SpellContext) return { spellState, searchSpell } } export default Hooker
BaseInfo上下文组件代码
function BaseInfo({ children }){ const [spellState, setSpellState] = useState({ name: undefined, desc: undefined, higher_level: undefined, range: undefined, components: undefined, material: undefined, ritual: false, duration: undefined, concentration: false, casting_time: undefined, level: 0, }); const searchSpell = (spellName) => { api.request(spellName).then(function(response) { setSpellState(prevState => ({ ...prevState, name: response.data.name, desc: response.data.desc, higher_level: response.data.higher_level, range: response.data.range, components: response.data.components, material: response.data.material, ritual: response.data.ritual, duration: response.data.duration, concentration: response.data.concentration, casting_time: response.data.duration, level: response.data.duration, }) ) }) console.log(spellState.duration) } const contextValue = { spellState, searchSpell: useCallback((spellName) => searchSpell(spellName), []), } return( <SpellContext.Provider value={contextValue}> {children} </SpellContext.Provider> ) } export default BaseInfo
问题原因与修复方案
报错xxx.default.request is not a function的直接原因是你导入的api对象上不存在request方法,从报错的webpack模块路径判断,问题出在你封装axios的api.js文件的导出/封装逻辑上:
- 先检查导入导出是否匹配:如果你在BaseInfo组件里用
import api from 'xxx/api.js'的默认导入写法,那api.js里必须用export default导出创建好的axios实例,不能写成命名导出export const api = xxx,否则你拿到的default导出是undefined或者空对象,自然找不到request方法。 - 再检查api封装逻辑:原生axios实例本身自带
.request()方法,如果你自己封装api的时候覆盖了默认导出,只导出了一个自定义了get/post方法的普通对象,没有保留request方法,调用时就会报这个错。如果你的咒语查询是GET请求,完全可以直接用api.get(请求地址)的写法,不用强行调用request。
正确的axios实例导出参考:
// 对应你的api.js文件 import axios from 'axios' const api = axios.create({ baseURL: '你后端接口的基础地址' }) export default api
修完api的问题,代码里还有几个会导致功能异常的bug,需要一并修改:
- 状态赋值笔误:更新spellState的时候,
casting_time和level两个字段你都错写成了response.data.duration,要对应接口返回的字段改对:casting_time: response.data.casting_time, level: response.data.level, - 异步逻辑打印错误:你在
api.request()调用后立刻写了console.log(spellState.duration),这时候接口请求还没返回,state还没更新,打印出来的永远是初始值undefined,要查看返回结果直接在then回调里打response.data就行,要监听state更新就加useEffect监听spellState变化。 - useCallback依赖错误:你给searchSpell包useCallback的时候依赖数组传了空数组,会一直缓存组件第一次渲染时的searchSpell方法,后续状态更新不会同步,依赖数组要加上searchSpell:
searchSpell: useCallback((spellName) => searchSpell(spellName), [searchSpell]), - 检查hooks导入:所有用到
useState/useContext/useCallback的文件,都要在顶部从react里导入这些方法,不然也会抛错。
内容的提问来源于stack exchange,提问作者Lucas Merlin
相关产品推荐
相关产品推荐

