从本地存储中删除时,React list.map 不是函数

问题描述

我正在开发一个预算跟踪应用,用户可以在其中添加不同的收入和支出。我正在使用 useReducer 来管理状态。每个收入和费用都是一个对象,当用户提交收入或费用时,它会显示为带有收入项目的收入列表或带有费用项目的费用列表。列表中的每个项目都有一个删除按钮,用于删除收入项目或费用项目。但是,例如,当我尝试单击删除按钮来删除收入项时,我收到一条错误消息,指出 list.map 不是函数

不确定为什么会发生这种情况,但我认为这与 IncomeOutputList.js 中的 removeItem 函数有关。删除收入项目的正确方法是什么?

App.js

import React,{ useState,useReducer } from 'react';
import './App.css';
import BudgetInput from './components/input/BudgetInput';
import Budgetoutput from './components/output/Budgetoutput';
import IncomeOutputList from './components/output/IncomeOutputList';
import ExpenSEOutputList from './components/output/ExpenSEOutputList';

const useSemiPersistentState = (key,initialState) => {
 // console.log(JSON.parse(localStorage.getItem(key)));
  const [value,setValue] = React.useState(
    localStorage.getItem(key) ? JSON.parse(localStorage.getItem(key)) : initialState
  );
  
  React.useEffect(()=>{
    localStorage.setItem(key,JSON.stringify(value));
  },[value,key])

  return [value,setValue];
};

const initialBudget = {
  description: '',type: '+',key: 'income',value: ''
};

const initialState = {
  incomes: [{}],expenses: [{}],budgetobj: initialBudget
};

const budgetReducer = (state,action) => {
  switch(action.type) {
    case "CHECK_STATE":
      console.log(state); //just to check state on submit
    case "ON_DESC_CHANGE":
      return {
        ...state,budgetobj: {
          ...state.budgetobj,description: action.payload
        }
      }
    case "ON_TYPE_CHANGE":
      const isExpense = action.payload === '-';
      return {
        ...state,type: action.payload,key: isExpense ? 'expense' : 'income'
        }
      }
    case "ON_VALUE_CHANGE":
      return {
        ...state,value: action.payload,}
      }
    case 'SUBMIT_BUDGET':
      console.log(state.incomes);
      const budget = {...state};
      const isIncome = budget.budgetobj.type === '+';
      return {
        incomes: isIncome ? state.incomes.concat(budget.budgetobj) : state.incomes,expenses: isIncome ? state.expenses : state.expenses.concat(budget.budgetobj),budgetobj: initialBudget,}
    case "REMOVE_ITEM":
      console.log('test');
      return {
        ...state,// not sure if the following line is the correct way to remove from local storage
        incomes: (index) => JSON.parse(localStorage.getItem("income")).splice(index,1),// expenses: (index) => JSON.parse(localStorage.getItem("expense")).splice(index,1)
      }
    default:
      return state;
  }
}

const useSemiPersistantReducer = (key,initialState) => {
  const [value,dispatch] = React.useReducer(
    budgetReducer,localStorage.getItem(key) ? JSON.parse(localStorage.getItem(key)) : initialState
  );

  React.useEffect(()=>{
    localStorage.setItem(key,dispatch]) //[inocmes,setIncomes]

  return [value,dispatch];
}


const App = () => {


 const [budgetState,setBudget] = useSemiPersistantReducer(initialState.budgetobj.key,initialState);

 const {incomes,expenses,budgetobj,key} = budgetState;

  return (
    <div className="App">
<link href="http://code.ionicframework.com/ionicons/2.0.1/css/ionicons.min.css" rel="stylesheet" type="text/css"></link>
      <div className="top">
        <Budgetoutput />
        
      </div>

      <div className="bottom">
        <BudgetInput 
          descValue={budgetobj.description || ''} //event.target.value
          onDescChange={event => setBudget({ type: "ON_DESC_CHANGE",payload: event.target.value })}
          onSelectChange={event => setBudget({ type: "ON_TYPE_CHANGE",payload: event.target.value })}
          type={budgetobj.type || ''}
          onBudgetSubmit={ () => setBudget({ type : 'SUBMIT_BUDGET' }) }
          budgetValue={budgetobj.value || ''}
          onValChange={event => setBudget({ type: "ON_VALUE_CHANGE",payload: event.target.value })}
        />

    
        <div className="container clearfix">
          <IncomeOutputList 
            list={incomes}
            removeIncome={ () => setBudget({ type: "REMOVE_ITEM" })} //not sure if this is correct?
          /> 
          <ExpenSEOutputList
            list={expenses}
           // removeExpense={(index)=>removeExp(index)}
          />
          
        </div>
        
      </div>

    </div>
  )
};


export default App;

收入输出.js

import React from 'react';
import IncomeOutput from './IncomeOutput';

// list will be list of income objects
const IncomeOutputList = ({ list,removeIncome }) => {

    return (
        <div className="income__list">
            <div className="income__list--title">INCOME</div>
            {list.map((item,index,arr) => <IncomeOutput 
                                id={item.id} 
                                value={item.value} 
                                type={item.type} 
                                desc={item.description} 
                                
                                // error has something to do with the following line?
                                handleButton={()=>removeIncome(index)}
                                />
            )}
        </div>
    )
}

export default IncomeOutputList;

收入输出.js

import React from 'react';
import ValueOutput from './ValueOutput';

const IncomeOutput = ({ desc,type,id,value,handleButton }) => {
   
        return (
            <>
                <div className="item clearfix income" id={id}>
                    <div className="item__description">{desc}</div>
                        <ValueOutput
                            type={type}
                            value={value}
                            handleClick={handleButton}
                        />
                </div>
            </>
        )
    }

export default IncomeOutput;

ValueOutput.js

import React from 'react';
import Button from '../buttons/Button';

const ValueOutput = ({type,handleClick}) => {
    
    return (
        <>
            <div className="right clearfix">
                <div className="item__value">{type} {value}</div>
                <Button buttonType="item__delete--btn" handler={handleClick}/>
            </div>
        </>
    )
}

export default ValueOutput;

Button.js

import React from 'react';

const Button = ({buttonType,handler}) => (
    <>
        <div className="item__delete">
            <button className={buttonType} onClick={handler}>
                <i className="ion-ios-close-outline"></i>
            </button>
        </div>
    </>
)

export default Button;

解决方法

我没有运行你的代码,只是猜测

收入:(index) => JSON.parse(localStorage.getItem("income")).splice(index,1),

incomes 是一个函数而不是数组,所以“incomes.map()”不存在。