React中SearchBox向Fetch URL传参报错:this.props.onSearchBox非函数
嘿,我来帮你搞定这个问题!你遇到的报错TypeError: this.props.onSearchBox is not a function是因为**SearchBox组件在App里渲染时没接收到onSearchBox这个回调props**,而且更深层的问题是你组件间的通信逻辑完全错了——不能把SearchBox组件直接塞进FetchMovie的请求URL里,组件是用来渲染UI的,不是传递数据的载体。咱们一步步来修复:
错误原因拆解
- 直接报错原因:你在
App组件里写的是<SearchBox />,没有传递onSearchBox这个props,但SearchBox的handleSubmit里却尝试调用this.props.onSearchBox,自然会抛出“不是函数”的错误。 - 核心逻辑错误:
FetchMovie里的fetchURL写法完全错误,<SearchBox onSearchBox={this.handleSubmit} />是JSX元素,不是字符串参数,不能直接拼进URL里。正确的做法是让父组件App作为中间层,管理搜索状态并传递给子组件。
具体修复步骤
步骤1:重构App组件,作为状态中间层
把App改成带状态的组件(用Hooks更简洁),用来存储用户输入的搜索关键词,同时给SearchBox传递回调,给FetchMovie传递搜索关键词:
import React, { useState } from 'react'; import './App.css'; import NavBar from './components/NavBar'; import SearchBox from './components/SearchBox'; import FetchMovie from './components/FetchMovie'; function App() { // 存储用户搜索的电影关键词 const [searchKeyword, setSearchKeyword] = useState(''); // 接收SearchBox传来的搜索值,更新状态 const handleSearch = (keyword) => { setSearchKeyword(keyword); }; return ( <> <NavBar /> {/* 给SearchBox传递onSearchBox回调 */} <SearchBox onSearchBox={handleSearch} /> {/* 把搜索关键词传给FetchMovie */} <FetchMovie searchKeyword={searchKeyword} /> </> ); } export default App;
步骤2:修复SearchBox组件的小问题
去掉handleChange里多余的e.preventDefault()(input的onChange事件不需要阻止默认行为),同时增加空值判断避免无效搜索:
// SearchBox组件 import React, { Component } from 'react'; class SearchBox extends Component { constructor(props) { super(props); this.state = { value: '' }; // 你用了箭头函数定义方法,不需要在constructor里bind } handleChange = (e) => { // 移除多余的preventDefault this.setState({value: e.target.value}); } handleSubmit = (e) => { e.preventDefault(); let userInput = this.state.value.trim(); if(userInput) { // 空值不触发搜索 this.props.onSearchBox(userInput); console.log(`You searched for the movie ${userInput}`); } } render() { return ( <div className="search-container"> <form className="form-search" onSubmit={this.handleSubmit}> <input type="text" value={this.state.value} onChange={this.handleChange} placeholder="Search Movie Title..." /> </form> <h5>{this.state.value}</h5> </div> ); } } export default SearchBox;
步骤3:重构FetchMovie组件,实现按需搜索
原来的componentDidMount只会在组件挂载时请求一次,而且请求方法和URL写法都错了。我们改成当搜索关键词变化时发起请求,同时处理各种异常情况:
// FetchMovie组件 import React, { Component } from 'react'; class FetchMovie extends Component { constructor(props) { super(props); this.state = { error: null, isLoading: false, data: {} }; // 电影数据是对象,不是数组 } // 抽离fetch请求方法 fetchMovie = (keyword) => { this.setState({ isLoading: true }); const API_KEY = 'dfbcc791'; // 用encodeURIComponent处理关键词,避免特殊字符破坏URL const url = `http://www.omdbapi.com/?apikey=${API_KEY}&t=${encodeURIComponent(keyword)}`; // OMDb接口是GET请求,不是POST,之前的POST会导致请求失败 fetch(url) .then(res => { if(!res.ok) throw new Error('网络请求失败'); return res.json(); }) .then(movie => { // 处理OMDb返回的“未找到电影”错误 if(movie.Error) { this.setState({ error: movie.Error, isLoading: false, data: {} }); } else { this.setState({ isLoading: false, data: movie, error: null }); } }) .catch(error => { this.setState({ isLoading: false, error: error.message }); }); } // 当搜索关键词变化时,发起新请求 componentDidUpdate(prevProps) { if(this.props.searchKeyword !== prevProps.searchKeyword && this.props.searchKeyword) { this.fetchMovie(this.props.searchKeyword); } } render() { const { error, isLoading, data } = this.state; if (error) { return <div>Error: {error}</div>; } else if (isLoading) { return <div>Loading...</div>; } else if(!Object.keys(data).length) { return <div>请输入电影名称进行搜索</div>; } else { return ( <div className="display"> <div className="column1"> {/* 处理海报不存在的情况 */} <img src={data.Poster !== 'N/A' ? data.Poster : 'https://via.placeholder.com/300x450?text=No+Poster'} alt={`${data.Title} poster`} /> </div> <div className="column2"> <h3>Title: {data.Title}</h3> <h6>Actors: {data.Actors}</h6> <h6>Year: {data.Year}</h6> <h6>Runtime: {data.Runtime}</h6> <h6>Rated: {data.Rated}</h6> <p>Plot: {data.Plot}</p> </div> </div> ); } } } export default FetchMovie;
关键修复点说明
- 修正了OMDb请求的方法:OMDb是GET请求,不是POST,之前的POST会导致请求失败;
- 增加了异常处理:包括网络错误、电影未找到的情况;
- 优化了数据逻辑:电影数据是对象不是数组,调整了state的初始值;
- 避免无效请求:只有当关键词变化且不为空时才发起请求;
- 处理了海报不存在的边界情况,避免页面出现破碎图片。
内容的提问来源于stack exchange,提问作者Chinonso
相关产品推荐
相关产品推荐

