从自定义函数调用useLazyQuery Hook无查询执行的问题排查
咱们一步一步拆解你遇到的问题:
1. 第一个无返回值的ShowUsers函数为何无效?
你写的第一个ShowUsers函数里,虽然调用了loadUsers(),但里面的JSX代码只是在函数内部“定义”了一遍,根本没有被插入到React组件的渲染树中。React只会渲染组件return语句里的内容,普通函数里的JSX如果不被组件的渲染输出引用,就完全不会被渲染出来。
另外,loadUsers()是异步的,调用后不会立刻更新data——要等GraphQL查询完成,组件才会因为data状态更新而重新渲染。但你的用户列表JSX不在组件的主渲染逻辑里,就算data更新了,这部分内容也不会被触发渲染。
2. 第二个返回JSX的ShowUsers函数为何还是不行?
你修改后的ShowUsers虽然返回了JSX,但你在onRequestSearch里只是调用了这个函数,并没有把它返回的JSX放到组件的return内容里。打个比方:你做了一份饭,但没把它端到餐桌上,自然没人能吃到。
而且,就算你当时把返回的JSX临时存起来,React的状态更新机制也不会追踪这部分内容——只有组件return里的元素,才会在状态(比如data)变化时重新渲染。你调用loadUsers()后,data会在未来某个时刻更新,但这时候ShowUsers返回的JSX已经是“过时”的了,也不会自动重新渲染。
正确的做法
其实不需要把渲染逻辑放到onRequestSearch的回调函数里,应该把渲染逻辑留在组件的主return中,用回调函数只负责触发查询:
// 保留这个只触发查询的函数 function ShowUsers() { console.log('Check'); loadUsers(); } // 组件的return还是原来的逻辑 return ( <div> <StyledSearchBar value={searchItem} onChange={value => setSearchItem(value)} onRequestSearch={ShowUsers} /> {/* 渲染逻辑始终在组件的return里,这样data更新时会自动重新渲染 */} {data && data.users.nodes && data.users.nodes.map((c: any, i: any) => ( <li key={c.id}> {/* 尽量用唯一id当key,别用索引 */} Id: {c.id}, First Name: {c.firstName}, Last Name: {c.lastName}, Email: {c.email}, phoneNumber: {c.phoneNumber} </li> ))} </div> );
如果一定要把渲染逻辑封装成函数,应该让它成为一个可复用的渲染函数,在组件的return里调用它,而不是在回调里:
// 定义一个渲染用户列表的函数,接收data作为参数 function renderUserList(data: any) { if (!data?.users?.nodes) return null; return ( <div> <Typography>Checking</Typography> {data.users.nodes.map((c: any, i: any) => ( <li key={c.id}> Id: {c.id}, First Name: {c.firstName}, Last Name: {c.lastName}, Email: {c.email}, phoneNumber: {c.phoneNumber} </li> ))} </div> ); } // 组件return里调用这个渲染函数 return ( <div> <StyledSearchBar value={searchItem} onChange={value => setSearchItem(value)} onRequestSearch={() => loadUsers()} /> {renderUserList(data)} </div> );
这样做的核心是:React组件的渲染内容必须在组件的return(或者被return的内容引用)里,只有这样,状态变化时React才能自动触发重新渲染,更新对应的内容。
内容的提问来源于stack exchange,提问作者user13101751

