从子级访问useState挂钩

时间:2020-09-17 21:41:29

标签: javascript reactjs react-native

现在,每个子项(SelectorButton)都可以打开和关闭,如果已打开,则在切换时该组件的标题将添加到父页面的“当前”数组中关闭,该组件的标题将从数组中弹出。我正在尝试对其进行设置,以便如果“当前”数组中有多个标题(至少按下了一个按钮),则可以看到“下一个”按钮。

我现在遇到的问题是控制按钮内容的if语句始终认为'current.length'== 0,这是因为它没有被重新渲染,而是查看初始首次加载页面时的“当前”状态。

我非常确定我需要使“当前”成为useState钩子,但不知道如何将该信息传递到每个组件中以便可以对其进行更新。很抱歉,如果该解释有点难以理解,我会很乐意回答任何问题。非常感谢所有帮助:)

父页面:

...
import SelectorButton from '../components/selectorButton';
const SignUpOne = ({ navigation }) => {
    //this gets updated as they click or click off a button
    //this hold the current pressed buttons
    //pretty sure this needs to be a state but Im not sure how to
    //pass this into children
    let current = []
    let nextButton

    if (current.length >= 1) {
        //next button is visible
        console.log('is visible')
        nextButton = <TouchableOpacity><Text>Next</Text></TouchableOpacity>
    } else {
        //its not visisble
        console.log('not visible')
        nextButton = <View></View>
    }

    const textFunction = () => {
        console.log(current)
    }

    return (


        <View style={styles.screen}>
            <ScrollView bounces={false}>
                <View style={{ margin: 20, flex: 1 }}>
                    {/*back button */}
                    <View style={{ width: '100%', flexDirection: 'row', justifyContent: 'space-between' }}>
                        <TouchableOpacity onPress={textFunction} style={styles.backButton}>
                            <Text>back</Text>
                        </TouchableOpacity>


                        <View style={styles.backButton}>
                            <Text>hi</Text>
                        </View>
                    </View>
                    <View style={styles.stepNotify}>
                        <Text style={styles.stepText}>Step 1 of 3</Text>
                    </View>

                    <Text style={styles.question}>What are you looking to improve?</Text>

                    {/*this is where the actual buttons are*/}
                    <View style={styles.optionContainer}>

                        {/*top row of buttons */}
                        <View style={{
                            flexDirection: 'row',
                            justifyContent: 'space-between',
                            width: '100%',
                        }}>
                            {/*actual button item */}
                            <SelectorButton array={current} title='Health'>
                                <Text>icon</Text>
                            </SelectorButton>

                            <SelectorButton array={current} title='???'>
                                <Text>icon</Text>
                            </SelectorButton>
                        </View>

                        {/*middle row of buttons */}
                        <View style={styles.rowContainer}>
                            {/*actual button item */}
                            <SelectorButton array={current} title='Relationships'>
                                <Text>icon</Text>
                            </SelectorButton>

                            <SelectorButton array={current} title='Time Allocation'>
                                <Text>icon</Text>
                            </SelectorButton>
                        </View>

                        {/*final row of buttons */}
                        <View style={styles.rowContainer}>
                            {/*actual button item */}
                            <SelectorButton array={current} title='Career'>
                                <Text>icon</Text>
                            </SelectorButton>

                            <SelectorButton array={current} title='Mental Health'>
                                <Text>icon</Text>
                            </SelectorButton>
                        </View>

                    </View>
                </View>
            </ScrollView>
        </View >
    )
}
export default SignUpOne
...

SelectorButton组件:

...
const SelectorButton = (props) => {
    //remember that it is rendered for each button seperatley
    //when active is == true, we want it to be added to an array,
    //if it is updated to false, we want to remove it from the array,
    //on submit, we want to push the remaining items to the user profile
    const [active, updateActive] = useState(false)
    //this has the

    const updateActiveHandler = () => {
        updateActive(prev => !prev)


        if (active == true) {
            console.log(props.title, 'is off')
            let index = props.array.indexOf(props.title)
            props.array.splice(index, 1)

        } else {
            console.log(props.title, 'is on')
            props.array.push(props.title)
        }
    }

    return (
        <View {...props} >
            {!active &&

                <View style={{ alignItems: 'center' }}>
                    <TouchableOpacity activeOpacity={1} onPress={updateActiveHandler} style={styles.selectionButton}>
                        {props.children}
                    </TouchableOpacity>
                    <Text style={styles.selectionButtonLabel}>{props.title}</Text>
                </View>
            }

            {active &&
                <View style={{ alignItems: 'center' }}>
                    <TouchableOpacity activeOpacity={1} onPress={updateActiveHandler} style={styles.pressedSelectionButton}>
                        {props.children}
                    </TouchableOpacity>
                    <Text style={styles.pressedSelectionLabel}>{props.title}</Text>
                </View>
            }


        </View>
    )
}

export default SelectorButton;
...

对于更多上下文,这是要呈现的页面,每个SelectorButton或Boxes,当至少按下一个按钮(显示为蓝色)时,下一个按钮将显示)还需要确保所有按下的按钮按钮已存储(在下一步注册步骤中添加到Firebase用户配置文件中)

enter image description here

2 个答案:

答案 0 :(得分:1)

是的

const [current, setCurrent] = useState([])
就我所知,

是正确的解决方案。然后只需将setCurrent函数作为道具传递给必要的孩子。之后,您将能够从子组件中更新电流。

答案 1 :(得分:-1)

就像已经回答的一些答案一样,您可以传递setState,实际上您可以传递任何内容。

拥有const [current, setCurrent] = useState("");时,您可以传递电流和setCurrent。

另一件事是,当您不需要状态但想要具有类属性之类的变量时,最好使用“ useRef”:

const whatever = useRef("");
whatever.current = "new value";
console.log(whatever.current) // new value

由let创建的具有普通变量的问题为您拥有变量“ current”,并使用一个空数组对其进行初始化,然后将其更改为其他变量,然后在组件重新渲染(因为状态已更改)后,current将再次使用该空数组进行初始化。

您可以认为,当您重新渲染组件时,就像是当react首次渲染您的组件时,唯一的区别是您的状态现在与第一个渲染不同。