简体   繁体   English

如何让一个组件停用另一个组件?

[英]How to have one component deactivate the other?

I am currently trying to write some buttons to sort a list.我目前正在尝试编写一些按钮来对列表进行排序。 When the user interacts with one button, the other needs to be nullified and reset to the "off state."当用户与一个按钮交互时,另一个按钮需要无效并重置为“关闭 state”。 The issue is that both can currently be activated.问题是两者当前都可以被激活。

在此处输入图像描述

as opposed to

在此处输入图像描述

My original plan for handling this was going to be by having the child buttons display based on their props, and write the logic to turn the other one off in the parent.我最初处理这个问题的计划是让子按钮根据它们的道具显示,并编写逻辑以在父级中关闭另一个按钮。 After I wrote this, I discovered that updating the props of the child would not cause it to re-render, thus it would never change shape.在我写完之后,我发现更新孩子的道具不会导致它重新渲染,因此它永远不会改变形状。

Instead, I wrote the logic for how a button appears in the button itself, leading me to my current dilemma: I can't get one button to tell the other to turn itself off.相反,我编写了按钮如何出现在按钮本身中的逻辑,这使我陷入了当前的困境:我无法让一个按钮告诉另一个按钮自行关闭。 Am I handling this wrong?我处理错了吗? How should I be doing this if so?如果是这样,我应该怎么做?

Parent code父代码

import React, { Component } from 'react';
import SortPlaylist from './sortPlaylist';
import Loader from './loader'
import IconButton from './iconButton'


class SortWrapper extends Component {
    state = { 
        isLoading: true,
        sortMode: "time",
        sortDirection: "linear",
    }

    async componentDidMount(){
        let plElement = <SortPlaylist origin="date" originVal="2021-01-11" sortBy="linear" loadFunc={this.updateLoad}></SortPlaylist>

        let iconButtons = [
            <IconButton key="time" sortBy="time" updateFunc={this.sortChange}/>,
            <IconButton key="votes" sortBy="votes" updateFunc={this.sortChange}/>
        ]

        this.setState({
            plElement,
            iconButtons
        })
    }

    updateLoad = () => {
        this.setState({
            isLoading: false
        })
    }
    
    sortChange = (sortBy) => {
        
    }

    render() { 
       

        return ( 
        <>  
            { this.state.isLoading ? <Loader /> : 
                <div className="sort-buttons">
                    {this.state.iconButtons}
                </div>
            }

            {this.state.plElement}
        </> 
        );
    }
}
 
export default SortWrapper;

Child code子代码

import React, { Component } from 'react';
import DownIcon from '../img/icons/arrow-down.svg'
import UpIcon from '../img/icons/arrow-up.svg'
import ClockIcon from '../img/icons/clock.svg'
import StarIcon from '../img/icons/star.svg'

class IconButton extends Component {
    state = {  }

    async componentDidMount(){

        let sortBy = this.props.sortBy;
        let active = this.props.active;

        this.setState({
            sortBy,
            active,
            disabled
        }, () => {
            this.updateMe(true)
        })

    }

    updateMe = (initial) => {
        let symbolElement = <></>
        let arrowElement = <></>
        let newActive = "none"
        
        if (this.state.sortBy==="time") {
            if(initial){
                symbolElement = <img className="icon-button" src={ClockIcon} alt="sort by time"/>
            }
            else if(this.state.active==="none"){
                symbolElement = <img className="icon-button active" src={ClockIcon} alt="sort by time"/>
                arrowElement = <img className="icon-button active" src={DownIcon} alt="down arrow"/>
                newActive="down"
            }
            else if(this.state.active==="down"){
                symbolElement = <img className="icon-button active" src={ClockIcon} alt="sort by time"/>
                arrowElement = <img className="icon-button active" src={UpIcon} alt="up arrow"/>
                newActive="up"
            }
            else if(this.state.active==="up"){
                symbolElement = <img className="icon-button" src={ClockIcon} alt="sort by time"/>
            }
        }

        
        if (this.state.sortBy==="votes") {
            if(initial){
                symbolElement = <img className="icon-button" src={StarIcon} alt="sort by votes"/>
            }
            else if(this.state.active==="none"){
                symbolElement = <img className="icon-button active" src={StarIcon} alt="sort by votes"/>
                arrowElement = <img className="icon-button active" src={DownIcon} alt="down arrow"/>
                newActive="down"
            }
            else if(this.state.active==="down"){
                symbolElement = <img className="icon-button active" src={StarIcon} alt="sort by votes"/>
                arrowElement = <img className="icon-button active" src={UpIcon} alt="up arrow"/>
                newActive="up"
            }
            else if(this.state.active==="up"){
                symbolElement = <img className="icon-button" src={StarIcon} alt="sort by votes"/>
            }
        }

        this.setState({
            symbolElement,
            arrowElement,
            active: newActive
        })
    }

    render() {

        return (
            <div className="icon-bundle" onClick={() => {
                this.props.updateFunc()
                this.updateMe(false)
            }}>
                {this.state.symbolElement}
                {this.state.arrowElement}
            </div>
        );
    }
}

export default IconButton;

Update #2:更新#2:

I tried @ppeko's answer, changing the code to the attached.我尝试了@ppeko 的答案,将代码更改为附件。

However, the buttons do not change appearance at all, despite the state that defines them having changed in the parent component.然而,这些按钮根本不会改变外观,尽管定义它们的 state 在父组件中已更改。 Why?为什么?

Parent code父代码

import React, { Component } from 'react';
import SortPlaylist from './sortPlaylist';
import Loader from './loader'
import IconButton from './iconButton'


class SortWrapper extends Component {
    state = { 
        isLoading: true,
        sortMode: "time",
        sortDirection: "linear",
        buttonStatus: [0, 0]
    }

    async componentDidMount(){
        let plElement = <SortPlaylist origin="date" originVal="2021-01-11" sortBy="linear" loadFunc={this.updateLoad}></SortPlaylist>

        let iconButtons = [
            <IconButton key="time" sortBy="time" updateFunc={this.sortChange} status={this.state.buttonStatus[0]}/>,
            <IconButton key="votes" sortBy="votes" updateFunc={this.sortChange} status={this.state.buttonStatus[1]}/>
        ]

        this.setState({
            plElement,
            iconButtons
        })
    }

    updateLoad = () => {
        this.setState({
            isLoading: false
        })
    }
    
    sortChange = (sortBy) => {
        console.log(sortBy + " called");
        console.log(this.state.buttonStatus);

        if(sortBy==="time"){
            this.setState({
                buttonStatus: [1,0]
            }, () => {
                console.log(this.state.buttonStatus);
            })
        }
    }

    render() { 
       

        return ( 
        <>  
            { this.state.isLoading ? <Loader /> : 
                <div className="sort-buttons">
                    {this.state.iconButtons}
                </div>
            }

            {this.state.plElement}
        </> 
        );
    }
}
 
export default SortWrapper;

Child code子代码

import React, { Component } from 'react';
import DownIcon from '../img/icons/arrow-down.svg'
import UpIcon from '../img/icons/arrow-up.svg'
import ClockIcon from '../img/icons/clock.svg'
import StarIcon from '../img/icons/star.svg'

class IconButton extends Component {
    state = {
        isLoading: true,
    }

    async componentDidMount(){
        const icon = this.getIcon();
        let locked = false;

        let iconCycle = [
           [<img key={this.props.sortBy} className="icon-button" src={icon} alt="sort by time"/>],
           [<img key={this.props.sortBy} className="icon-button active" src={icon} alt="sort by time"/>, 
           <img key="down" className="icon-button active" src={DownIcon} alt="down arrow"/>],
           [<img key={this.props.sortBy} className="icon-button active" src={icon} alt="sort by time"/>, 
           <img key="up" className="icon-button active" src={UpIcon} alt="up arrow"/>]
        ]

        if(this.props.status===0){
            locked = true;
        }

        this.setState({
            iconCycle,
            isLoading: false,
            locked
        })
    }

    getIcon = () => {
        if(this.props.sortBy==="time"){
            return ClockIcon
        }
        else if(this.props.sortBy==="votes"){
            return StarIcon
        }
    }

    updateMe = (initial) => {
        
    }

    render() {

        return (
            <div className="icon-bundle" onClick={() => {
                this.updateMe(false)
                this.props.updateFunc(this.props.sortBy)
            }}>
            {this.state.isLoading ? <></> : 
                this.state.locked ? this.state.iconCycle[0] :
                    this.state.iconCycle[1]
            }
            </div>
        );
    }s
}

export default IconButton;

I am currently trying to write some buttons to sort a list.我目前正在尝试编写一些按钮来对列表进行排序。 When the user interacts with one button, the other needs to be nullified and reset to the "off state."当用户与一个按钮交互时,另一个按钮需要无效并重置为“关闭 state”。 The issue is that both can currently be activated.问题是两者当前都可以被激活。

在此处输入图像描述

as opposed to

在此处输入图像描述

My original plan for handling this was going to be by having the child buttons display based on their props, and write the logic to turn the other one off in the parent.我最初处理这个问题的计划是让子按钮根据它们的道具显示,并编写逻辑以在父级中关闭另一个按钮。 After I wrote this, I discovered that updating the props of the child would not cause it to re-render, thus it would never change shape.在我写完之后,我发现更新孩子的道具不会导致它重新渲染,因此它永远不会改变形状。

Instead, I wrote the logic for how a button appears in the button itself, leading me to my current dilemma: I can't get one button to tell the other to turn itself off.相反,我编写了按钮如何出现在按钮本身中的逻辑,这使我陷入了当前的困境:我无法让一个按钮告诉另一个按钮自行关闭。 Am I handling this wrong?我处理错了吗? How should I be doing this if so?如果是这样,我应该怎么做?

Parent code父代码

import React, { Component } from 'react';
import SortPlaylist from './sortPlaylist';
import Loader from './loader'
import IconButton from './iconButton'


class SortWrapper extends Component {
    state = { 
        isLoading: true,
        sortMode: "time",
        sortDirection: "linear",
    }

    async componentDidMount(){
        let plElement = <SortPlaylist origin="date" originVal="2021-01-11" sortBy="linear" loadFunc={this.updateLoad}></SortPlaylist>

        let iconButtons = [
            <IconButton key="time" sortBy="time" updateFunc={this.sortChange}/>,
            <IconButton key="votes" sortBy="votes" updateFunc={this.sortChange}/>
        ]

        this.setState({
            plElement,
            iconButtons
        })
    }

    updateLoad = () => {
        this.setState({
            isLoading: false
        })
    }
    
    sortChange = (sortBy) => {
        
    }

    render() { 
       

        return ( 
        <>  
            { this.state.isLoading ? <Loader /> : 
                <div className="sort-buttons">
                    {this.state.iconButtons}
                </div>
            }

            {this.state.plElement}
        </> 
        );
    }
}
 
export default SortWrapper;

Child code子代码

import React, { Component } from 'react';
import DownIcon from '../img/icons/arrow-down.svg'
import UpIcon from '../img/icons/arrow-up.svg'
import ClockIcon from '../img/icons/clock.svg'
import StarIcon from '../img/icons/star.svg'

class IconButton extends Component {
    state = {  }

    async componentDidMount(){

        let sortBy = this.props.sortBy;
        let active = this.props.active;

        this.setState({
            sortBy,
            active,
            disabled
        }, () => {
            this.updateMe(true)
        })

    }

    updateMe = (initial) => {
        let symbolElement = <></>
        let arrowElement = <></>
        let newActive = "none"
        
        if (this.state.sortBy==="time") {
            if(initial){
                symbolElement = <img className="icon-button" src={ClockIcon} alt="sort by time"/>
            }
            else if(this.state.active==="none"){
                symbolElement = <img className="icon-button active" src={ClockIcon} alt="sort by time"/>
                arrowElement = <img className="icon-button active" src={DownIcon} alt="down arrow"/>
                newActive="down"
            }
            else if(this.state.active==="down"){
                symbolElement = <img className="icon-button active" src={ClockIcon} alt="sort by time"/>
                arrowElement = <img className="icon-button active" src={UpIcon} alt="up arrow"/>
                newActive="up"
            }
            else if(this.state.active==="up"){
                symbolElement = <img className="icon-button" src={ClockIcon} alt="sort by time"/>
            }
        }

        
        if (this.state.sortBy==="votes") {
            if(initial){
                symbolElement = <img className="icon-button" src={StarIcon} alt="sort by votes"/>
            }
            else if(this.state.active==="none"){
                symbolElement = <img className="icon-button active" src={StarIcon} alt="sort by votes"/>
                arrowElement = <img className="icon-button active" src={DownIcon} alt="down arrow"/>
                newActive="down"
            }
            else if(this.state.active==="down"){
                symbolElement = <img className="icon-button active" src={StarIcon} alt="sort by votes"/>
                arrowElement = <img className="icon-button active" src={UpIcon} alt="up arrow"/>
                newActive="up"
            }
            else if(this.state.active==="up"){
                symbolElement = <img className="icon-button" src={StarIcon} alt="sort by votes"/>
            }
        }

        this.setState({
            symbolElement,
            arrowElement,
            active: newActive
        })
    }

    render() {

        return (
            <div className="icon-bundle" onClick={() => {
                this.props.updateFunc()
                this.updateMe(false)
            }}>
                {this.state.symbolElement}
                {this.state.arrowElement}
            </div>
        );
    }
}

export default IconButton;

Update #2:更新#2:

I tried @ppeko's answer, changing the code to the attached.我尝试了@ppeko 的答案,将代码更改为附件。

However, the buttons do not change appearance at all, despite the state that defines them having changed in the parent component.然而,这些按钮根本不会改变外观,尽管定义它们的 state 在父组件中已更改。 Why?为什么?

Parent code父代码

import React, { Component } from 'react';
import SortPlaylist from './sortPlaylist';
import Loader from './loader'
import IconButton from './iconButton'


class SortWrapper extends Component {
    state = { 
        isLoading: true,
        sortMode: "time",
        sortDirection: "linear",
        buttonStatus: [0, 0]
    }

    async componentDidMount(){
        let plElement = <SortPlaylist origin="date" originVal="2021-01-11" sortBy="linear" loadFunc={this.updateLoad}></SortPlaylist>

        let iconButtons = [
            <IconButton key="time" sortBy="time" updateFunc={this.sortChange} status={this.state.buttonStatus[0]}/>,
            <IconButton key="votes" sortBy="votes" updateFunc={this.sortChange} status={this.state.buttonStatus[1]}/>
        ]

        this.setState({
            plElement,
            iconButtons
        })
    }

    updateLoad = () => {
        this.setState({
            isLoading: false
        })
    }
    
    sortChange = (sortBy) => {
        console.log(sortBy + " called");
        console.log(this.state.buttonStatus);

        if(sortBy==="time"){
            this.setState({
                buttonStatus: [1,0]
            }, () => {
                console.log(this.state.buttonStatus);
            })
        }
    }

    render() { 
       

        return ( 
        <>  
            { this.state.isLoading ? <Loader /> : 
                <div className="sort-buttons">
                    {this.state.iconButtons}
                </div>
            }

            {this.state.plElement}
        </> 
        );
    }
}
 
export default SortWrapper;

Child code子代码

import React, { Component } from 'react';
import DownIcon from '../img/icons/arrow-down.svg'
import UpIcon from '../img/icons/arrow-up.svg'
import ClockIcon from '../img/icons/clock.svg'
import StarIcon from '../img/icons/star.svg'

class IconButton extends Component {
    state = {
        isLoading: true,
    }

    async componentDidMount(){
        const icon = this.getIcon();
        let locked = false;

        let iconCycle = [
           [<img key={this.props.sortBy} className="icon-button" src={icon} alt="sort by time"/>],
           [<img key={this.props.sortBy} className="icon-button active" src={icon} alt="sort by time"/>, 
           <img key="down" className="icon-button active" src={DownIcon} alt="down arrow"/>],
           [<img key={this.props.sortBy} className="icon-button active" src={icon} alt="sort by time"/>, 
           <img key="up" className="icon-button active" src={UpIcon} alt="up arrow"/>]
        ]

        if(this.props.status===0){
            locked = true;
        }

        this.setState({
            iconCycle,
            isLoading: false,
            locked
        })
    }

    getIcon = () => {
        if(this.props.sortBy==="time"){
            return ClockIcon
        }
        else if(this.props.sortBy==="votes"){
            return StarIcon
        }
    }

    updateMe = (initial) => {
        
    }

    render() {

        return (
            <div className="icon-bundle" onClick={() => {
                this.updateMe(false)
                this.props.updateFunc(this.props.sortBy)
            }}>
            {this.state.isLoading ? <></> : 
                this.state.locked ? this.state.iconCycle[0] :
                    this.state.iconCycle[1]
            }
            </div>
        );
    }s
}

export default IconButton;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM