Реакция: Uncaught TypeError: tokenIds.map не является функцией - PullRequest
1 голос
/ 17 января 2020

Я использую React для генерации компонентов из массива, который находится в состоянии через хуки. Инициализированный массив работает без проблем, но перестает работать после обновления его состояния:

export function AiShip(props) {
    const shipType = props.shipType;
    const maxShields = Ships[shipType][Stats.shields];
    const maxHull = Ships[shipType][Stats.hull];
    const squadId = props.squadId;

    const [targetPosition, setTargetPosition] = useState([PSN.FARFRONT]);
    const [tokenIds, setTokenIds] = useState([3, 4]); //todo remove initial values

    function handleTokenIdChange(value, index) {
        const tTokenIds = tokenIds;
        tTokenIds.splice(index, 1, value);
        setTokenIds(...tTokenIds);
        };


    return (
        <div>
            <h1>{Ships[props.shipType][Stats.name]}</h1>
            <div className="row">
                <div className="col-6">
                    <ShipStats shipType={shipType}/>
                    <div className="row ">
                        <div className="col-4">
                            <h3>ID:</h3>
                        </div>
                        <div className="col-4">
                            <h3>Shields:</h3>
                        </div>
                        <div className="col-4">
                            <h3>Hull:</h3>
                        </div>
                    </div>
                    {
                        tokenIds.map( (tokenId) =>
                             <ShipVariables key={tokenIds.indexOf(tokenId)} maxShields={maxShields} maxHull={maxHull}
                                           tokenIdIndex={tokenIds.indexOf(tokenId)}
                                           handleTokenIdChange={handleTokenIdChange}/>)
                    }
                    <br/>

Состояние обновляется с помощью функции handleTokenIdChange. Полученный массив все еще является массивом (я проверял это с помощью функции Array.isArray). Код для запуска обновления состояния приведен здесь:

<div className="col-4">
                    <Select options={idOptions} onChange={e => props.handleTokenIdChange(e.value, props.tokenIdIndex)}/>
                </div>

Я знаю, что обычно проблема заключается в том, что переменная - это не массив, а, например, объект, но здесь это не так. Результатом остается массив, хранящий число. Выбор позволяет пользователю выбрать одно из следующих значений:

const idOptions = [
        {value: 0, label: 0},
        {value: 1, label: 1},
        {value: 2, label: 2},
        {value: 3, label: 3},
        {value: 4, label: 4},
        {value: 5, label: 5},
        {value: 6, label: 6},
        {value: 7, label: 7},
        {value: 8, label: 8},
        {value: 9, label: 9},
    ];

Это стек ошибок:

AiShip.js:49 Uncaught TypeError: tokenIds.map is not a function
    at AiShip (AiShip.js:49)
    at renderWithHooks (react-dom.development.js:16260)
    at updateFunctionComponent (react-dom.development.js:18347)
    at beginWork$1 (react-dom.development.js:20176)
    at HTMLUnknownElement.callCallback (react-dom.development.js:336)
    at Object.invokeGuardedCallbackDev (react-dom.development.js:385)
    at invokeGuardedCallback (react-dom.development.js:440)
    at beginWork$$1 (react-dom.development.js:25780)
    at performUnitOfWork (react-dom.development.js:24698)
    at workLoopSync (react-dom.development.js:24671)
    at performSyncWorkOnRoot (react-dom.development.js:24270)
    at react-dom.development.js:12199
    at unstable_runWithPriority (scheduler.development.js:697)
    at runWithPriority$2 (react-dom.development.js:12149)
    at flushSyncCallbackQueueImpl (react-dom.development.js:12194)
    at flushSyncCallbackQueue (react-dom.development.js:12182)
    at discreteUpdates$1 (react-dom.development.js:24423)
    at discreteUpdates (react-dom.development.js:1438)
    at dispatchDiscreteEvent (react-dom.development.js:5881)
    ```

Ответы [ 2 ]

2 голосов
/ 17 января 2020

Проблема здесь, в функции handleTokenIdChange:

setTokenIds(...tTokenIds);

tTokenIds - это массив, но ...tTokenIds не:

let myArray = [1,2,3]
console.log(...myArray) // 1 2 3

Так что вы не может использовать .map на нем.

Решение

Учитывая контекст, я предполагаю, что вы пытались использовать деструктуризацию для создания копии вашего массива. Вместо ...tTokenIds необходимо использовать [...tTokenIds]:

let myArray = [1,2,3]
console.log([...myArray]) // [1, 2, 3]

Вы также можете использовать Array.prototype.slice() для создания копии массива:

console.log(myArray.slice()) // [1, 2, 3]

Важно для знать

Обратите внимание, что создание копии вашего объекта состояния до и внесение в него каких-либо изменений - это лучшая практика:

function handleTokenIdChange(value, index) {
    const tTokenIds = [...tokenIds];
    tTokenIds.splice(index, 1, value);
    setTokenIds(tTokenIds);
}
1 голос
/ 17 января 2020

Когда вы распространяете массив через

setTokens(...tTokenIds)

Ваше состояние больше не становится массивом, каждый элемент извлекается как отдельное значение во время распространения. Поэтому, скорее всего, это просто приведет к тому, что первый элемент массива станет состоянием, а остальные будут игнорироваться, поэтому map больше не представляется возможным.

Вам нужно распространить массив в новый массив, т.е. [...tTokenIds], или вы можете просто использовать tTokenIds.slice() для клонирования массива.

Обратите внимание, что это не будет клонировать элементы, уже находящиеся в массиве, они все равно будут такими же экземплярами из предыдущего массив

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...