Reactjs 反应:未捕获类型错误:tokenIds.map不是函数

Reactjs 反应:未捕获类型错误:tokenIds.map不是函数,reactjs,react-hooks,Reactjs,React Hooks,我使用React通过钩子从处于状态的数组生成组件。初始化的数组正在正常工作,但在更新其状态后停止工作: export function AiShip(props) { const shipType = props.shipType; const maxShields = Ships[shipType][Stats.shields]; const maxHull = Ships[shipType][Stats.hull]; const squadId = props

我使用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/>
这是错误堆栈:

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)
    ```

问题在这里,在
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);
}

问题在这里,在
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);
}

当您通过

setTokens(...tTokenIds)
您的状态不再成为数组,在排列过程中,每个项目都被提取为单个值。因此,它很可能只会导致数组的第一项成为状态,其余项被忽略,因此
map
不再可能

您需要将数组扩展到一个新数组中,即
[…tTokenIds]
,或者您可以使用
tTokenIds.slice()
克隆数组


请注意,这不会克隆阵列中已存在的项目,当您通过扩展阵列时,它们仍然是上一个阵列中的相同实例

setTokens(...tTokenIds)
您的状态不再成为数组,在排列过程中,每个项目都被提取为单个值。因此,它很可能只会导致数组的第一项成为状态,其余项被忽略,因此
map
不再可能

您需要将数组扩展到一个新数组中,即
[…tTokenIds]
,或者您可以使用
tTokenIds.slice()
克隆数组


请注意,这不会克隆阵列中已经存在的项,它们仍然是前一个阵列中的相同实例

,这很有趣M谢谢-但是为什么更新后调用的array.isArray(tokenIds)返回true?您能建议一种更新数组的正确方法吗?在使用spread运算符后,它是否返回true?我似乎无法重现这一点。在我的示例中,
Array.isArray(…myArray)
返回
false
是,它返回了:tTokenIds.splice(索引,1,值);setTokenId([…TTokenId]);log(“新令牌ID:”);console.log(令牌ID);log(“Is-array:+array.isArray(tokenIds));返回true,控制台中的对象是一个数组,具有更新的值。但你的修改工作如约,非常感谢!这很有趣,谢谢-但是为什么更新后调用的Array.isArray(tokenIds)返回true呢?您能建议一种更新数组的正确方法吗?在使用spread运算符后,它是否返回true?我似乎无法重现这一点。在我的示例中,
Array.isArray(…myArray)
返回
false
是,它返回了:tTokenIds.splice(索引,1,值);setTokenId([…TTokenId]);log(“新令牌ID:”);console.log(令牌ID);log(“Is-array:+array.isArray(tokenIds));返回true,控制台中的对象是一个数组,具有更新的值。但你的修改工作如约,非常感谢!