在react中将其作为prop传递时出现错误setValue is not a function

问题描述 投票:0回答:1

我试图根据子组件的子组件中给出的输入来更新一些

useState()
变量的值,但在调用它时不断收到错误,指出
setItem()
中的
setValue()
useState()
函数声明不是函数。

这是声明和引用它们的父级代码:

import React, {useEffect, useState} from "react"
import "./Creation.css"
import Header from "../components/Header"
import Footer from "../components/Footer"
import CreatorSurface from "../components/Creator/CreatorSurface"
import ProfilePic from "../assets/profile.png"
// import { AttributeContextProvider, useAttributeContext } from "../contexts/AttributeContext"


export default function Creation() {
    const [strength, setStrength] = useState("10")
    const [dexterity, setDexterity] = useState("10")
    const [constitution, setConstitution] = useState("10")
    const [intelligence, setIntelligence] = useState("10")
    const [wisdom, setWisdom] = useState("10")
    const [charisma, setCharisma] = useState("10")

    const [item, setItem] = useState()
    const [value, setValue] = useState()

    useEffect(() => {
        switch (item) {
            case "Strength":
                setStrength(value)
                break;
            case "Dexterity":
                setDexterity(value)
                break;
            case "Constitution":
                setConstitution(value)
                break;
            case "Intelligence":
                setIntelligence(value)
                break;
            case "Wisdom":
                setWisdom(value)
                break;
            case "Charisma":
                setCharisma(value)
                break;
            default:
                console.log("selector not recognized")
        }
    }, [item, value])

    return (
        <>
            <Header />
            <div className="creator">
                <h1 className="creator-title">Character Creator</h1>
                <div className="creator-banner">
                    <img className="profile" alt="Profile" src={ProfilePic}/>
                    <div className="character-details">
                        <h1 className="character-name">Character Name</h1>
                        <h2>race class</h2>
                    </div>
                    <div className="banner-atr">
                        <label for="str">Strength: </label>
                        <p name="str">{strength}</p>
                        <label for="dex">Dexterity: </label>
                        <p name="dex">{dexterity}</p>
                        <label for="con">Constitution: </label>
                        <p name="con">{constitution}</p>
                        <label for="int">Intelligence: </label>
                        <p name="int">{intelligence}</p>
                        <label for="wis">Wisdom: </label>
                        <p name="wis">{wisdom}</p>
                        <label for="cha">Charisma: </label>
                        <p name="cha">{charisma}</p>
                    </div>
                </div>
                <CreatorSurface setItem={setItem} setValue={setValue}/>
            </div>
            <Footer />
        </>
    )
}

“中间人”代码:

import React, { useState } from "react"
import CreatorDetails from "./CreatorDetails"
import CreatorClasses from "./CreatorClasses"
import CreatorRaces from "./CreatorRaces"
import CreatorEquipment from "./CreatorEquipment"
import "./CreatorSurface.css"


export default function CreatorSurface({ setItem, setValue }) {
    const [isSelected, setIsSelected] = useState()

    const handleClick = (e) => {
        const id = e.target.id;
        setIsSelected(id);
        console.log(id);
    };

    const renderChild = () => {
        switch (isSelected) {
            case "details":
                return <CreatorDetails setItem={setItem} setValue={setValue}/>
            case "race":
                return <CreatorRaces />
            case "class": 
                return <CreatorClasses />
            case "equipment":
                return <CreatorEquipment />
            default:
                return <CreatorDetails />
        }
    }

    return (
        <div className="parent">
            <div className="selector">
                <h1>Create your character using the sections below</h1>
                <button onClick={handleClick} id="details" >Details</button>
                <button onClick={handleClick} id="race" >Race</button>
                <button onClick={handleClick} id="class" >Class</button>
                <button onClick={handleClick} id="equipment" >Equipment</button>
                <button onClick={handleClick} id="save" >Save Character</button>
                <button onClick={handleClick} id="sheet" >Character Sheet</button>
            </div>
            {renderChild()}
        </div>
    )
}

以及我想要更新的组件:

import React, {useState} from "react";
import "./CreatorSub.css"
import Details from "./Details/Details";
// import { useAttributeContext } from "../../contexts/AttributeContext"


export default function CreatorDetails({ setItem, setValue }) {

    // list of options
    const options = [
        {
            label: '16',
            value: '16'
        },
        {
            label: '14',
            value: '14'
        },
        {
            label: '14',
            value: '14-1'
        },
        {
            label: '12',
            value: '12'
        },
        {
            label: '12',
            value: '12-1'
        },
        {
            label: '10',
            value: '10'
        }
    ]

    // list of select names
    const selectNames = [
        "Strength",
        "Dexterity",
        "Constitution",
        "Intelligence",
        "Wisdom",
        "Charisma"
    ]

    const [chosenOptions, setChosenOptions] = useState({});


    // remove the option when chosen by another selector
    const isChosenByOther = (optionValue, selectName) => {
        for (let key in chosenOptions) {
            if (key !== selectName) {
                if (chosenOptions[key] === optionValue) {
                    return true;
                }
            }
        }
        return false;
    };

    const handleChange = (ev) => {
        setChosenOptions({...chosenOptions, [ev.target.name]: ev.target.value});
        let value = ""
        if (ev.target.value === "14-1") {
           value = "14"
        } else if (ev.target.value === "12-1") {
            value = "12"
        } else {value = ev.target.value}
        setItem(ev.target.name)
        setValue(value)
    };

    // Runs through the list of selector names provided above and creates the neccessary elements with corresponding labels
    const selectRender = selectNames.map((name, index) => {
        return (
            <>
                <label for={name}>{name}:</label>
                <select name={name} key={index} onChange={handleChange} value={chosenOptions[name] || ''}
                        required={index === 0} id={name}>
                    <option value=''/>
                    {options.filter(({value}) => !isChosenByOther(value, name))
                        .map(({label, value}, oIndex) =>
                            <option value={value} key={oIndex}>{label}</option>)
                    }
                </select>
            </>
        )
    })

    return (
        <div className="sub-parent">
            <div className="sub-selector">
                <div id="char-info">
                    <label for="char-name">Name:</label>
                    <input type="text" id="char-name" name="char-name" />
                    <label for="level">Level:</label>
                    <select name="level" id="level" type="submit">
                        <option value="1">1</option>
                        <option value="1">2</option>
                        <option value="1">3</option>
                        <option value="1">4</option>
                        <option value="1">5</option>
                        <option value="1">6</option>
                        <option value="1">7</option>
                        <option value="1">8</option>
                        <option value="1">9</option>
                        <option value="1">10</option>
                        <option value="1">11</option>
                        <option value="1">12</option>
                        <option value="1">13</option>
                        <option value="1">14</option>
                        <option value="1">15</option>
                        <option value="1">16</option>
                        <option value="1">17</option>
                        <option value="1">18</option>
                        <option value="1">19</option>
                        <option value="1">20</option>
                    </select>
                </div>
                <div id="attributes" >
                    <h1>Character Attributes</h1>
                    <p>Characters have 6 Defining Scores: Strength (Str), Constitution (Con), Dexterity (Dex), 
                        Intelligence (Int), Wisdom (Wis), and Charisma (Cha). As your character will essentially 
                        be a combination of statistics and ability scores, it is important to define which scores 
                        should be higher or lower to match what type of character you want to play. 
                    </p>
                    <p>Each character will be given the same pool of 6 numbers to choose from to divide between 
                        the Defining Scores (be aware that your choice of race will increase or decrease different scores); 
                        16, 14, 14, 12, 12, and 10.
                    </p>
                    <div className="atr-selectors">
                        {selectRender}
                    </div>
                </div>
            </div>
            <Details />
        </div>
        
    )
}

当我通过

setItem
函数调用
setValue
组件中的
CreatorDetails
handleChange
函数时,我收到错误,它不是函数。希望当
<select>
组件中的
CreatorDetails
标签更改值时,它将立即反映在
Creation
组件中,因为它们位于同一页面视图上。不确定是什么阻止了它将其识别为函数。任何帮助将不胜感激。

reactjs react-hooks react-props
1个回答
0
投票

在您的

renderChild
方法中,默认情况下不会为
setItem
setValue
属性传递任何值。由于
isSelected
被初始化为
null
,默认情况就是最初渲染的情况。

建议更改:

const renderChild = () => {
        switch (isSelected) {
            case "details":
                return <CreatorDetails setItem={setItem} setValue={setValue} />
            case "race":
                return <CreatorRaces />
            case "class": 
                return <CreatorClasses />
            case "equipment":
                return <CreatorEquipment />
            default:
                return <CreatorDetails setItem={setItem} setValue={setValue} />
        }
    }

PS——这是说明 TypeScript 为何有价值的教科书示例。如果您为

CreatorDetails
属性指定了类型,您的 IDE 会在适当的位置显示错误;)

© www.soinside.com 2019 - 2024. All rights reserved.