如何在Redux切片文件中调用组件内定义的函数?
问题解决方案
核心问题是你不应该在Redux状态中存储React元素——Redux的设计初衷是存储可序列化的纯数据,而非包含组件闭包引用的UI元素。下面是具体的修正方案:
1. 修改Redux Thunk:只返回纯数据
把原来在thunk里生成<i>标签的逻辑去掉,仅返回API数据和操作标识,让UI层负责渲染交互元素:
export const getNomads = createAsyncThunk("applicant/getNomads", async(data) => { const { searchParam, pageNum } = data; let nomadObj = { isPending: true, bodyArray: [] }; const response = await axios.get(`https://demo.khedmatashayer-kj.ir/api/v1/nomad/${pageNum}?${searchParam}`, config); if (response.data) { const array = response.data.map((item) => { // 仅存储数据和操作类型标识,不生成React元素 return [ { type: 'edit', data: item }, { type: 'history', data: { name: item.name, nomadId: item.nomad_id } }, // 原有的其他数据字段... item.name, item.nomad_id, // ...其他需要展示的字段 ]; }); nomadObj = { isPending: false, bodyArray: array }; } return nomadObj; });
2. 通过Context传递事件处理函数
因为UserInformationTable是MyComponent的后代组件,用React Context跨层级传递操作函数,避免props层层传递:
第一步:创建操作Context
// TableActionsContext.js import { createContext, useContext } from 'react'; const TableActionsContext = createContext({ handleShowForm: () => {}, handleShowHistory: () => {}, }); export const useTableActions = () => useContext(TableActionsContext); export default TableActionsContext;
第二步:在MyComponent中提供Context
import TableActionsContext from './TableActionsContext'; const MyComponent = () => { const handleShowForm = (arg) => { // 你的原逻辑 }; const handleShowHistory = (arg1, arg2) => { // 你的原逻辑 }; useEffect(() => { dispatch(getNomads({ searchParam: '', pageNum: 1 // 修正原代码的拼写错误:pagaNum → pageNum })); }, []); // 添加依赖数组,避免无限循环 return ( <TableActionsContext.Provider value={{ handleShowForm, handleShowHistory }}> {/* 渲染UserInformationTable或其上层组件 */} <UserInformationTable /> </TableActionsContext.Provider> ); };
3. 在表格组件中渲染交互元素
修改UserInformationTable,根据纯数据渲染按钮并绑定Context提供的事件函数:
import { useTableActions } from './TableActionsContext'; const UserInformationTable = () => { const { headArray, bodyArray, searchedBodyArray, statusStyle } = useContext(MyContext); const { handleShowForm, handleShowHistory } = useTableActions(); const data = searchedBodyArray?.length > 0 ? searchedBodyArray : bodyArray; const isPending = useSelector(selectIsPending); // 统一处理单元格内容渲染 const renderCell = (entry) => { if (entry.type === 'edit') { return ( <i className="fa fa-edit edit" onClick={() => handleShowForm(entry.data)} ></i> ); } if (entry.type === 'history') { return ( <i className="fa fa-file-text-o records" onClick={() => handleShowHistory(entry.data.name, entry.data.nomadId)} ></i> ); } // 普通数据直接返回 return entry; }; return ( <table className='user-table'> <thead> <tr> {headArray.map((item, index) => ( <th key={index}>{item}</th> ))} </tr> </thead> {isPending ? ( <tbody> <tr><td colSpan='100'><Loading /></td></tr> </tbody> ) : ( <tbody> {(data?.length === 0 || data[0] === 'موردی یافت نشد') ? ( <tr><td className='empty-table' colSpan='100%'>موردی یافت نشد</td></tr> ) : ( data?.map((item, index) => ( <tr key={index}> {item.map((entry, index1) => ( <td key={index1} className='table-entry' style={index1 === 12 ? statusStyle[index] : {}} > {renderCell(entry)} </td> ))} <td>{toFarsiNumber(index + 1)}</td> </tr> )) )} </tbody> )} </table> ); };
方案优势
- 符合Redux设计原则:状态只存纯数据,避免序列化问题和闭包引用导致的意外bug
- 职责分离:数据获取层(thunk)只负责拿数据,UI层负责渲染交互逻辑
- 灵活扩展:其他不需要操作按钮的组件,只需不提供
TableActionsContext或传入空函数即可
内容的提问来源于stack exchange,提问作者Arman Ebrahimi
相关产品推荐
相关产品推荐

