React中如何向独立路由访问的子组件传递函数?
Hey,我来帮你理清楚这个问题哈!你遇到的Uncaught TypeError: _this.props.onSubmit is not a function报错,核心原因很简单:
当你直接通过路由http://localhost:3000/bar访问SearchBar时,这个组件是由React Router直接渲染的,并没有经过LandingPage作为父组件传递onSubmit这个props。之前你只是在LandingPage里用CSS把SearchBar隐藏了,但路由直接渲染的SearchBar完全没拿到这个函数,自然就报错了。
下面给你两种可行的解决思路:
方案1:新增顶层共同父组件(基于React Router 4)
最直接的办法是创建一个顶层的App组件,让它作为LandingPage和SearchBar的共同父组件,把共享的搜索逻辑函数放在这里,然后通过路由的箭头函数渲染方式,把函数作为props传递给SearchBar。这样不管是从LandingPage里显示(隐藏)的SearchBar,还是路由直接访问的SearchBar,都能拿到正确的props。
修改后的代码示例
顶层App.js
export default class App extends React.Component{ constructor(props){ super(props) this.state = { articalName: "Landing page" }; } // 共享的搜索提交函数,放在顶层父组件 onSearchSubmit = term => { console.log(term); // 这里可以添加你的业务逻辑,比如发起搜索请求、更新全局状态等 } render(){ return( <div> <Route path="/" exact component={LandingPage} /> <Route path="/admin" component={() => <Admin title={this.state.articalName} />} /> <Route path="/posts" component={Post} /> <Route path="/categories" component={Categories} /> <Route path="/users" component={Users} /> <Route path="/details" component={Details} /> <Route path="/profile" component={Profile} /> <Route path="/weatherapp" component={weatherApp} /> {/* 通过箭头函数渲染SearchBar,传递onSubmit props */} <Route path="/bar" component={() => <SearchBar onSubmit={this.onSearchSubmit} />} /> </div> ) } }
LandingPage.js(可选调整)
如果LandingPage里的SearchBar也需要使用同一个搜索函数,你可以让App把onSearchSubmit传递给LandingPage,再由它传给SearchBar:
export default class LandingPage extends React.Component { render() { return ( <div> <div className="admin"> {/* 接收App传递的函数,再传给SearchBar */} <SearchBar onSubmit={this.props.onSearchSubmit} /> </div> {/* 其他页面内容 */} </div> ) } }
SearchBar.js(保持原有逻辑,小优化)
export default class SearchBar extends React.Component{ state = {term: ''}; onFormSubmit = event => { event.preventDefault(); // 现在不管哪种渲染方式,props.onSubmit都存在了 this.props.onSubmit(this.state.term); }; render(){ return( <div> <div className="container"> <div className="searchBar mt-5"> <form onSubmit={this.onFormSubmit}> <div className="form-group"> {/* React里要把label的for改成htmlFor,避免和JS的for关键字冲突 */} <label htmlFor="search">Image search</label> <input type="text" className="form-control" placeholder="Search..." value={this.state.term} onChange={e => this.setState({term: e.target.value})} /> </div> </form> </div> </div> </div> ) } }
方案2:使用Redux(或其他状态管理库)
如果你的应用规模较大,有多个组件需要共享搜索状态或者处理搜索逻辑,用状态管理库会更优雅。你可以把搜索关键词存在全局状态中,SearchBar负责触发action更新这个状态,而需要用到搜索结果的组件(比如LandingPage或其他页面)只需要订阅全局状态即可,完全不需要手动传递函数props。
这种方式能让组件之间彻底解耦,不管SearchBar在哪里渲染,都能和全局状态交互,适合复杂应用的场景。
总结
你之前的方式(只在父组件隐藏子组件)确实不可行,因为路由直接渲染的子组件根本拿不到父组件的props。通过新增顶层父组件传递props,或者使用状态管理库,都能完美解决这个问题。如果是小型应用,第一种方案简单直接;如果应用比较复杂,状态管理会是更合适的选择。
内容的提问来源于stack exchange,提问作者user9347049

