Ошибка типа: list.map не является функцией

#javascript #reactjs #web #components #typeerror

#javascript #reactjs #веб #Компоненты #ошибка типа

Вопрос:

Я создаю приложение для практики реагирования, и я получаю сообщение об ошибке при попытке сохранить массив объектов в локальном хранилище. Я новичок в React, поэтому я не уверен, что происходит. Я получаю ошибку в компоненте IncomeOutputList, потому что я пытаюсь перечислить кучу объектов, используя массив.

Вот мой код:

Компонент приложения:

 import React, { useState, useReducer } from 'react';
   import BudgetInput from './components/input/BudgetInput';
   import IncomeOutputList from './components/output/IncomeOutputList';
   import IncomeOutput from './components/output/IncomeOutput';

const useSemiPersistentState = (key, initialState) => {
  const [value, setValue] = React.useState(
    localStorage.getItem(key) || initialState
  );
  
  React.useEffect(()=>{
    localStorage.setItem(key, JSON.stringify(value));
  }, [value, key])

  return [value, setValue];
};

const App = () => {
  const [incomes, setIncomes] = useSemiPersistentState('income',[{}]);
  const [description, setDescription] = useState('');
  const [type, setType] = useState(' ');
  const [value, setValue] = useState('');

  const incomeObj = {
    desc: description,
    budgetType: type,
    incomeValue: value
  }

  const handleIncomeObjArray = () => {
    setIncomes(incomes.concat(incomeObj));
    console.log(incomes   "testing");
  }

  const handleChange = (event) => {  //this handler is called in the child component BudgetInput
    setDescription(event.target.value);
  }

  const handleSelectChange = (event) => {  //this handler is called in the child component BudgetInput
    setType(event.target.value);
  }

  const handleValueChange = (event) => {
    setValue(event.target.value);
    console.log(incomeObj)
  }

  return (
    <div className="App">

      <div className="top">

        
      </div>

      <div className="bottom">
        <BudgetInput 
          descValue={description}
          onDescChange={handleChange}
          onSelectChange={handleSelectChange}
          type={type}
          onBudgetSubmit={handleIncomeObjArray}
          budgetValue={value}
          onValChange={handleValueChange}
        />

        {/* <IncomeOutput 
          obj={incomeObj}
        /> */}

        {/* <IncomeOutput 
          desc={description}
          type={type}
        /> */}

        <IncomeOutputList 
          list={incomes}
        /> 
      </div>

    </div>
  )
};
  

Компонент IncomeOutputList:

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


// list will be list of income objects
const IncomeOutputList = ({ list }) => {
    return (
        <div>
            {list.map(item => <IncomeOutput 
                                id={item.id} 
                                value={item.incomeValue} 
                                type={item.budgetType} 
                                desc={item.desc}  
                              />)}
        </div>
    )
}

export default IncomeOutputList;
  

Компонент IncomeOutput:

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

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

export default IncomeOutput;
  

РЕДАКТИРОВАТЬ: вот codesandbox для этого кода: https://codesandbox.io/s/busy-shirley-bwhv2?file=/src/App.js:2394-2509

Комментарии:

1. Обычно это означает, что список не является массивом, поэтому он не может иметь функцию map . Я подозреваю, что список не определен из prop. Возможно, создайте codepen, чтобы мы могли точно определить ошибку.

Ответ №1:

Это потому, что ваш пользовательский редуктор возвращает строку, а не массив

попробуйте это

 const useSemiPersistentState = (key, initialState) => {
  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];
};
  

Комментарии:

1. Это может быть потому localStorage.getItem(key) , что может быть null в первый раз. Измените его io localStorage.getItem(key) amp;amp; JSON.parse(localStorage.getItem(key)) || initialState

2. Как насчет React.useState(localStorage.GetItem(ключ) ? JSON.parse(localStorage.GetItem(ключ)) : начальное состояние)

3. @Nithish да, похоже, пока это работает, спасибо!

4. @alti21 Очистите ваш localStorage (уверен, что у вас там недопустимый json) и поместите try catch вокруг JSON.parse(), чтобы в случае сбоя вы могли удалить его с помощью localStorage.remoteItem(key) и использовать initialState по умолчанию