Javascript state.map在发送时不是一个函数

Javascript state.map在发送时不是一个函数,javascript,reactjs,react-hooks,frontend,Javascript,Reactjs,React Hooks,Frontend,我有一个react组件,它使用useReducer钩子处理动态文本字段的添加和删除。 预计工作如下: 类型“add”将用一个或多个空对象追加当前状态。添加按钮的onClick事件 类型“remove”将从状态数组中删除对象。删除按钮的onClick事件 使用状态变量上的映射函数渲染字段。 但是当我尝试使用add/remove分派时,state.map函数将变得未定义。 任何形式的帮助都是非常感激的 代码片段 export default function Create(props) {

我有一个react组件,它使用useReducer钩子处理动态文本字段的添加和删除。 预计工作如下:

类型“add”将用一个或多个空对象追加当前状态。添加按钮的onClick事件 类型“remove”将从状态数组中删除对象。删除按钮的onClick事件 使用状态变量上的映射函数渲染字段。 但是当我尝试使用add/remove分派时,state.map函数将变得未定义。 任何形式的帮助都是非常感激的

代码片段

export default function Create(props) {
    const initialState = [{}];

    function reducer(state, action) {
        switch (action.type) {
            case 'add':
                state = {...state}
                console.log(state)
                return state;
            case 'remove':
                return state;
            default:
                throw new Error();
        }
    }

    const {dialogOpen, data} = {...props}
    const [open, setOpen] = React.useState(false);
    const [state, dispatch] = React.useReducer(reducer, initialState)


    return (
        <div>
                    {
                        state.map(() => {
                            return (
                                <div style={{display: "flex", alignItems: "center"}}>
                                    <ApplicationBudget/>
                                    <IconButton style={{marginLeft: 10}} onClick={() => dispatch({type: 'remove'})}
                                                aria-label="delete" margin={{margin: 2}}>
                                        <DeleteOutlined/>
                                    </IconButton>
                                    <IconButton aria-label="add" onClick={() => dispatch({type: 'add'})}
                                                margin={{margin: 1}}>
                                        <Add/>
                                    </IconButton>
                                </div>
                            )
                        })
                    }

        </div>
    );
}

您的初始状态是一个数组:

initialState = [{}]
因此state.map作为数组的原型有一个map方法

但是,在减速器中,返回一个对象:

state = {...state}
您的对象没有贴图方法

这里有两个问题:

您不应该修改state变量,而应该让它保持不变,并返回一个新的状态。一种常见的工作方式是将当前状态扩展到返回状态。 您需要保持类型稳定,因此返回数组,而不是对象。 例如:

 function reducer(state, action) {
        switch (action.type) {
            case 'add':
                return [...state, "new entry"];
        }
    }
更新:我为您添加了一个最小的示例。它有一个具有两个动作的减速器。一个和你有同样错误行为的人,一个正常工作的人

功能应用程序{ const reducer=状态,action=>{ 开关动作类型{ 案例添加-断开:{ 返回{…状态}; } 案例添加工作:{ 返回[…状态,…操作.有效负载]; } 默认值:{ 抛出新的错误; } } }; const[state,dispatch]=React.usereducer,['a','b']; 回来 {state.maps=>{s} 分派{type:'add breaked',payload:'C'}}>add breaked 分派{type:'add working',payload:'C'}}>add working ; } ReactDOM.render、document.getElementByIdapp; 谢谢fjc的帮助。 以下面的解决方案结束

export default function Create(props) {
    const initialState = [{}];

    function reducer(state, action) {
        switch (action.type) {
            case 'add':
                return [...state, ...action.payload]
            case 'remove':
                let newState = [...state]
                newState.splice(action.payload, 1)
                return newState
            default:
                throw new Error();
        }
    }

    const {dialogOpen, data} = {...props}
    const [open, setOpen] = React.useState(false);
    const [state, dispatch] = React.useReducer(reducer, initialState)

    return (
        <div>
                    {

                        state.map((budget, index) => {
                            return (
                                <div key={index} style={{display: "flex", alignItems: "center"}}>
                                    <ApplicationBudget/>
                                    <IconButton style={{marginLeft: 10}}
                                                onClick={() => dispatch({type: 'remove', payload: index })}
                                                aria-label="delete" margin={{margin: 2}}>
                                        <DeleteOutlined/>
                                    </IconButton>
                                    <IconButton aria-label="add"
                                                onClick={() => dispatch({type: 'add', payload: [{}]})}
                                                margin={{margin: 1}}>
                                        <Add/>
                                    </IconButton>
                                </div>
                            )
                        })


                    }
        </div>
    );
}