简体   繁体   中英

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." 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:

I tried @ppeko's answer, changing the code to the attached.

However, the buttons do not change appearance at all, despite the state that defines them having changed in the parent component. 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." 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:

I tried @ppeko's answer, changing the code to the attached.

However, the buttons do not change appearance at all, despite the state that defines them having changed in the parent component. 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;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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