使用useReducer时Kendo React Grid无法进入单元格编辑的问题咨询
Kendo React Grid 结合 useReducer 实现单元格编辑与排序示例
核心问题在于使用useReducer时,必须保证状态更新的不可变性——Kendo Grid依赖状态的引用变化触发重新渲染,直接修改原状态会导致Grid无法感知到变化,从而无法进入编辑模式。以下是完整的实现示例,包含单元格编辑、排序功能:
完整代码实现
import { useReducer } from 'react'; import { Grid, GridColumn } from '@progress/kendo-react-grid'; import { process } from '@progress/kendo-data-query'; // 定义reducer的action类型 const ACTION_TYPES = { START_EDIT: 'START_EDIT', UPDATE_CELL: 'UPDATE_CELL', END_EDIT: 'END_EDIT', SORT: 'SORT' }; // 状态初始化 const initialState = { data: [ { id: 1, name: 'John Doe', age: 30, email: 'john@example.com' }, { id: 2, name: 'Jane Smith', age: 25, email: 'jane@example.com' }, { id: 3, name: 'Bob Brown', age: 35, email: 'bob@example.com' } ], editField: '', sort: [], editedItem: null }; // reducer函数,处理所有状态更新逻辑 function gridReducer(state, action) { switch (action.type) { case ACTION_TYPES.START_EDIT: return { ...state, editedItem: action.payload.item, editField: action.payload.field }; case ACTION_TYPES.UPDATE_CELL: // 不可变更新数据:创建新数组,替换修改后的项 const updatedData = state.data.map(item => item.id === action.payload.item.id ? { ...item, [action.payload.field]: action.payload.value } : item ); return { ...state, data: updatedData, editedItem: { ...action.payload.item, [action.payload.field]: action.payload.value } }; case ACTION_TYPES.END_EDIT: return { ...state, editedItem: null, editField: '' }; case ACTION_TYPES.SORT: return { ...state, sort: action.payload.sort }; default: return state; } } export default function GridWithReducer() { const [state, dispatch] = useReducer(gridReducer, initialState); // 处理单元格点击,进入编辑模式 const handleCellClick = (event) => { if (event.dataItem && event.field) { dispatch({ type: ACTION_TYPES.START_EDIT, payload: { item: event.dataItem, field: event.field } }); } }; // 处理单元格内容变化 const handleChange = (event) => { dispatch({ type: ACTION_TYPES.UPDATE_CELL, payload: { item: state.editedItem, field: event.target.name, value: event.target.value } }); }; // 处理编辑结束(比如失去焦点) const handleBlur = () => { dispatch({ type: ACTION_TYPES.END_EDIT }); }; // 处理排序变化 const handleSortChange = (event) => { dispatch({ type: ACTION_TYPES.SORT, payload: { sort: event.sort } }); }; // 使用kendo-data-query的process函数处理排序后的数据 const processedData = process(state.data, { sort: state.sort }).data; // 自定义编辑单元格渲染 const renderEditCell = (props) => { if (props.dataItem === state.editedItem && props.field === state.editField) { return ( <td> <input name={props.field} value={props.dataItem[props.field]} onChange={handleChange} onBlur={handleBlur} autoFocus /> </td> ); } return <td>{props.dataItem[props.field]}</td>; }; return ( <Grid data={processedData} onCellClick={handleCellClick} sortable={true} onSortChange={handleSortChange} sort={state.sort} > <GridColumn field="name" title="Name" cell={renderEditCell} /> <GridColumn field="age" title="Age" cell={renderEditCell} /> <GridColumn field="email" title="Email" cell={renderEditCell} /> </Grid> ); }
关键要点说明
- 不可变状态更新:在reducer中修改数据时,始终创建新的数组/对象(如
state.data.map、{ ...item }),绝对不能直接修改原状态对象,否则Grid无法检测到变化。 - 编辑状态管理:通过
editedItem和editField跟踪当前编辑的单元格,点击单元格时触发START_EDITaction,更新时触发UPDATE_CELL,失去焦点时触发END_EDIT。 - 排序集成:将排序状态存入reducer,通过
handleSortChange更新排序配置,使用process函数处理数据排序,确保排序后的数据正确渲染。 - 自定义单元格渲染:通过
cell属性自定义单元格,判断当前单元格是否处于编辑状态,渲染输入框或普通文本。
内容的提问来源于stack exchange,提问作者sfaust
相关产品推荐
相关产品推荐

