Next.js搜索组件报TypeError: Cannot read properties of undefined (reading 'toLowerCase')
问题描述
基于Next.js开发Web应用时,复制了其他可正常运行项目的搜索组件代码,但输入搜索内容时触发两个错误:
TypeError: Cannot read properties of undefined (reading 'toLowerCase')- 后续修改代码后又出现
ReferenceError: props is not defined
相关代码如下:
/lib/posts.js
import fs from 'fs' import path from 'path' import matter from 'gray-matter' import remark from 'remark' import html from 'remark-html' const postsDirectory = path.join(process.cwd(), 'posts') export function getSortedPostsData() { // Get file names under /posts const fileNames = fs.readdirSync(postsDirectory) const allPostsData = fileNames.map(fileName => { // Remove ".md" from file name to get id const id = fileName.replace(/\.md$/, '') // Read markdown file as string const fullPath = path.join(postsDirectory, fileName) const fileContents = fs.readFileSync(fullPath, 'utf8') // Use gray-matter to parse the post metadata section const matterResult = matter(fileContents) // Combine the data with the id return { id, ...matterResult.data } }) // Sort posts by date return allPostsData.sort((a, b) => { if (a.date < b.date) { return 1 } else { return -1 } }) }
/pages/api/search.js
import { getSortedPostsData } from '../../lib/posts' const posts = process.env.NODE_ENV === 'production' ? require('../../cache/data').posts : getSortedPostsData() export default (req, res) => { const results = req.query.q ? posts.filter(post => post.title.toLowerCase().includes(req.query.q)) : [] res.statusCode = 200 res.setHeader('Content-Type', 'application/json') res.end(JSON.stringify({ results })) }
/components/Search.js
import { useCallback, useRef, useState } from 'react'; import Link from 'next/link'; import styles from './search.module.css'; export default function Search() { const searchRef = useRef(null) const [query, setQuery] = useState('') const [active, setActive] = useState(false) const [results, setResults] = useState([]) const searchEndpoint = (query) => `/api/search?q=${query}` const onChange = useCallback((event) => { const query = event.target.value; setQuery(query) if (query.length) { fetch(searchEndpoint(query)) .then(res => res.json()) .then(res => { setResults(res.results) }) } else { setResults([]) } }, []) const onFocus = useCallback(() => { setActive(true) window.addEventListener('click', onClick) }, []) const onClick = useCallback((event) => { if (searchRef.current && !searchRef.current.contains(event.target)) { setActive(false) window.removeEventListener('click', onClick) } }, []) return ( <div className={styles.container} ref={searchRef} > <input className={styles.search} onChange={onChange} onFocus={onFocus} placeholder='Search posts' type='text' value={query} /> { active && results.length > 0 && ( <ul className={styles.results}> {results.map(({ id, title }) => ( <li className={styles.result} key={id}> <Link href="/posts/[id]" as={`/posts/${id}`}> <a>{title}</a> </Link> </li> ))} </ul> ) } </div> ) }
错误信息
error - TypeError: Cannot read properties of undefined (reading 'toLowerCase') at eval (webpack-internal:///(api)/./pages/api/search.js:12:67) at Array.filter (<anonymous>) at __WEBPACK_DEFAULT_EXPORT__ (webpack-internal:///(api)/./pages/api/search.js:12:41) at Object.apiResolver (/home/konstantin/Projects/next-linearjs-docs/node_modules/next/dist/server/api-utils/node.js:184:15) at processTicksAndRejections (node:internal/process/task_queues:96:5) at async DevServer.runApi (/home/konstantin/Projects/next-linearjs-docs/node_modules/next/dist/server/next-server.js:403:9) at async Object.fn (/home/konstantin/Projects/next-linearjs-docs/node_modules/next/dist/server/base-server.js:493:37) at async Router.execute (/home/konstantin/Projects/next-linearjs-docs/node_modules/next/dist/server/router.js:222:36) at async DevServer.run (/home/konstantin/Projects/next-linearjs-docs/node_modules/next/dist/server/base-server.js:612:29) at async DevServer.run (/home/konstantin/Projects/next-linearjs-docs/node_modules/next/dist/server/dev/next-dev-server.js:569:20) { page: '/api/search' } 5 | export default (req, res) => { 6 | const results = req.query.q ? > 7 | posts.filter(post => post.title.toLowerCase().includes(req.query.q)) : [] | ^ 8 | res.statusCode = 200 9 | res.setHeader('Content-Type', 'application/json') 10 | res.end(JSON.stringify({ results })) event - compiled client and server successfully in 6.7s (581 modules) wait - compiling /api/search... event - compiled successfully in 1697 ms (103 modules) error - (api)/pages/api/search.js (7:56) @ eval error - ReferenceError: props is not defined at eval (webpack-internal:///(api)/./pages/api/search.js:12:87) at Array.filter (<anonymous>) at __WEBPACK_DEFAULT_EXPORT__ (webpack-internal:///(api)/./pages/api/search.js:12:41) at Object.apiResolver (/home/konstantin/Projects/next-linearjs-docs/node_modules/next/dist/server/api-utils/node.js:184:15) at processTicksAndRejections (node:internal/process/task_queues:96:5) at async DevServer.runApi (/home/konstantin/Projects/next-linearjs-docs/node_modules/next/dist/server/next-server.js:403:9) at async Object.fn (/home/konstantin/Projects/next-linearjs-docs/node_modules/next/dist/server/base-server.js:493:37) at async Router.execute (/home/konstantin/Projects/next-linearjs-docs/node_modules/next/dist/server/router.js:222:36) at async DevServer.run (/home/konstantin/Projects/next-linearjs-docs/node_modules/next/dist/server/base-server.js:612:29) at async DevServer.run (/home/konstantin/Projects/next-linearjs-docs/node_modules/next/dist/server/dev/next-dev-server.js:569:20) { page: '/api/search' } 5 | export default (req, res) => { 6 | const results = req.query.q ? > 7 | posts.filter(post => props.post.title.toLowerCase().includes(req.query.q)) : [] | ^ 8 | res.statusCode = 200 9 | res.setHeader('Content-Type', 'application/json') 10 | res.end(JSON.stringify({ results }))
错误原因分析
第一个错误:TypeError: Cannot read properties of undefined (reading 'toLowerCase')
这个错误指向post.title.toLowerCase(),说明你的文章中至少有一篇没有title字段。
原因在于/lib/posts.js的getSortedPostsData函数会读取posts目录下所有md文件的元数据(通过gray-matter解析),并将元数据与id合并返回。如果某篇md文件的元数据块里没写title,对应的post对象就会缺少title属性,调用toLowerCase()时自然会触发报错。另外如果生产环境用了缓存数据require('../../cache/data').posts,也可能存在缓存中部分文章缺失title的情况。
第二个错误:ReferenceError: props is not defined
这是你修改代码时的低级失误——在这个API路由函数里根本不存在props变量,错误地把post.title改成了props.post.title,属于语法错误。
解决方案
解决toLowerCase()报错
- 检查所有md文章的元数据:确保每篇文章的md文件开头的gray-matter块都包含
title字段,示例:
--- title: "我的第一篇文章" date: "2024-01-01" ---
- 添加空值保护:在搜索过滤时先判断
post.title是否存在,同时把搜索关键词也转成小写,实现大小写不敏感搜索,修改/pages/api/search.js的过滤逻辑:
const results = req.query.q ? posts.filter(post => post.title && post.title.toLowerCase().includes(req.query.q.toLowerCase())) : []
- 验证缓存数据:如果生产环境使用了缓存,确保缓存生成时所有文章都包含
title字段,避免缓存数据缺失属性。
解决props is not defined报错
把错误的props.post.title改回post.title即可,保持正确的变量引用。
内容的提问来源于stack exchange,提问作者Константин Водолажский
相关产品推荐
相关产品推荐

