如何将App.js中的搜索相关逻辑抽离为独立的Search.js组件
React搜索逻辑抽离到独立组件的解决方案
问题背景
我正在学习Robin Wieruch所著的《The Road To React》,书中案例全部将代码写在App.js文件中,不符合最佳开发实践。我已经将其他模块都抽离为独立组件文件,但无法将搜索相关逻辑抽离到单独的Search.js文件中,当前文件夹结构如下:
现有可运行代码
App.js代码
import React, { useState } from 'react'; import './App.css'; import Greeting from '../Greeting/Greeting'; import Search from '../Search/Search'; import List from '../List/List'; const useSemiPersistentState = (key, initialState) => { const [value, setValue] = React.useState( localStorage.getItem(key) || initialState ); React.useEffect(() => { localStorage.setItem(key, value); }, [value, key]); return [value, setValue] }; // App组件 const App = () => { const stories = [ { title: 'React', url: 'https://reactjs.org/', author: 'Jordan Walke', num_comments: 3, points: 4, objectID: 0, }, { title: 'Redux', url: 'https://redux.js.org/', author: 'Dan Abramov, Andrew Clark', num_comments: 2, points: 5, objectID: 1, }, ]; // 用自定义Hook设置searchTerm、setSearchTerm状态 const [searchTerm, setSearchTerm] = useSemiPersistentState( 'search', 'React' ); // 获取搜索框输入值 const handleSearch = (event) => { setSearchTerm(event.target.value); }; // 匹配用户输入与stories数组内容,统一转小写判断 const searchedStories = stories.filter((story) => story.title.toLowerCase().includes(searchTerm.toLowerCase()) ); // 渲染 return ( <div className="App"> <Greeting name="Colin" age="28" occupation="Front-end developer" /> <InputWithLabel id="search" value={searchTerm} isFocused onInputChange={handleSearch} > <strong>Search:</strong> </InputWithLabel> <hr /> <List list={searchedStories} /> </div> ); } // 搜索框组件,解构props const InputWithLabel = ({ id, value, type = "text", onInputChange, isFocused, children, }) => { const inputRef = React.useRef(); React.useEffect(() => { if (isFocused && inputRef.current) { inputRef.current.focus(); } }, [isFocused]); return ( <> <label htmlFor={id}>{children}</label> <input ref={inputRef} id={id} type={type} value={value} autoFocus={isFocused} onChange={onInputChange} /> </> ) } export default App;
List组件代码
import React from 'react'; import Item from '../Item/Item'; function List({ list }) { return ( <ul> {list.map(({ objectID, ...item }) => ( <Item key={objectID} {...item} /> ))} </ul> ); } export default List;
Item组件代码
import React from 'react'; function Item({ title, url, author, num_comments, points }) { return ( <div> <li> <span> <a href={url}>{title}</a> </span> <span> {author}</span> <span> {num_comments} comments,</span> <span> {points} points.</span> </li> </div> ); } export default Item;
Greeting组件和Helpers文件夹与本次问题无关,暂不提供代码。
抽离时遇到的错误
将搜索相关代码移动到Search.js并在App.js中导入后触发如下编译错误:
编译失败
src/Components/App/App.js
第60行第8列: 'InputWithLabel' 未定义 react/jsx-no-undef
第62行第16列: 'searchTerm' 未定义 no-undef
第64行第24列: 'handleSearch' 未定义 no-undef
第69行第19列: 'searchedStories' 未定义 no-undef
解决步骤
报错是因为你把InputWithLabel组件抽离后,App.js中没有对应定义,也没有将搜索需要的状态和方法通过props传递给抽离后的Search组件,按以下步骤修改即可:
1. 编写Search/Search.js文件
import React from 'react'; const InputWithLabel = ({ id, value, type = "text", onInputChange, isFocused, children, }) => { const inputRef = React.useRef(); React.useEffect(() => { if (isFocused && inputRef.current) { inputRef.current.focus(); } }, [isFocused]); return ( <> <label htmlFor={id}>{children}</label> <input ref={inputRef} id={id} type={type} value={value} autoFocus={isFocused} onChange={onInputChange} /> </> ) } const Search = ({ searchTerm, handleSearch }) => { return ( <InputWithLabel id="search" value={searchTerm} isFocused onInputChange={handleSearch} > <strong>Search:</strong> </InputWithLabel> ) } export default Search;
2. 修改App.js文件
删除App.js中原来的InputWithLabel组件定义,将模板中的InputWithLabel替换为导入的Search组件,传入需要的props:
import React, { useState } from 'react'; import './App.css'; import Greeting from '../Greeting/Greeting'; import Search from '../Search/Search'; import List from '../List/List'; const useSemiPersistentState = (key, initialState) => { const [value, setValue] = React.useState( localStorage.getItem(key) || initialState ); React.useEffect(() => { localStorage.setItem(key, value); }, [value, key]); return [value, setValue] }; const App = () => { const stories = [ { title: 'React', url: 'https://reactjs.org/', author: 'Jordan Walke', num_comments: 3, points: 4, objectID: 0, }, { title: 'Redux', url: 'https://redux.js.org/', author: 'Dan Abramov, Andrew Clark', num_comments: 2, points: 5, objectID: 1, }, ]; const [searchTerm, setSearchTerm] = useSemiPersistentState( 'search', 'React' ); const handleSearch = (event) => { setSearchTerm(event.target.value); }; const searchedStories = stories.filter((story) => story.title.toLowerCase().includes(searchTerm.toLowerCase()) ); return ( <div className="App"> <Greeting name="Colin" age="28" occupation="Front-end developer" /> <Search searchTerm={searchTerm} handleSearch={handleSearch} /> <hr /> <List list={searchedStories} /> </div> ); } export default App;
修改后所有报错会消失,功能和原代码完全一致。
内容的提问来源于stack exchange,提问作者Halp_am_stuck
相关产品推荐
相关产品推荐

