简体   繁体   中英

ReactJS: How to change state property value in a component, when the state property value in another component is a certain value

I am working on a React application and I am using Redux to store the state. I have the following code.

menu.component.jsx:

import React, { Component } from 'react';
import { connect } from 'react-redux';

import MenuCategory from '../../components/menu-category/menu-category.component'
import NewCategoryButton from '../../components/new-category-button/new-category-button.component';
import EditMenuButton from '../../components/edit-menu-button/edit-menu-button.component';

import './menu.styles.scss';

class MenuPage extends Component {

    state = {
        menuEditable: false
    }

    render() {

        return (
            <div className='menu-page'>
                {this.props.menu ? this.props.menu.map(category => <MenuCategory key={category._id} {...category} />) : null}
                <div className='edit-menu-buttons'>
                    <div className='menu-button'>
                        {this.props.currentUser ? <NewCategoryButton /> : null}
                    </div>
                    <div className='menu-button'>
                        {this.props.currentUser ? <EditMenuButton /> : null}
                    </div>
                </div>
            </div>
        )
    }
}

const mapStateToProps = state => ({
    currentUser: state.user.currentUser,
    menu: state.menu
})

export default connect(mapStateToProps)(MenuPage);

edit-menu-button.component.jsx:

import React, { Component } from 'react';
import { connect } from 'react-redux';

import Button from '../button/button.component';

class EditMenuButton extends Component {

    state = {
        text: "Edit Menu"
    }

    changeText = () => {
        const { text } = this.state;
        if(text === "Edit Menu") {
            this.setState({text: "Save Edits"});
        } else {
            this.setState({text: "Edit Menu"});
        }
    }

    render() {
        const { text } = this.state;

        return (
            <Button onClick={ () => { this.changeText()} } style={{ backgroundColor: text === "Save Edits" ? "#b9edee" : "#222222", color: text === "Save Edits" ? "#000000" : "#ffffff", border: text === "Save Edits" ? "none" : "1px solid #222222"}}>{text}</Button>
        );
    }
}

export default (EditMenuButton);

I have a EditMenuButton component that has a state with a text property, and a MenuPage component that has a state with a menuEditable property.

When the text property in EditMenuButton component has a value of 'Save Edits' , I want the menuEditable property in the MenuPage component to have a value of true .

I have data that is external to the components in my application that make up the Redux store (eg using the createStore() function). However, I am not sure how to make the state property value change when the state is inside a component, as in the case of the MenuPage and EditMenuButton components. Any insights are appreciated.

Usually its best practice in React to store state in parents, and flow that down into the children through props, focusing on having one single source of truth for the state of your application.

Consider only having menuEditable in your MenuPage , and passing that into MenuButton through a prop:

class MenuPage extends Component {

    state = {
        menuEditable: false
    }

    toggleMenuEditable = () => {
        this.setState((state) => ({
            menuEditable: !state.menuEditable;
        }));
    }

    render() {

        return (
            <div className='menu-page'>
                {this.props.menu ? this.props.menu.map(category => <MenuCategory key={category._id} {...category} />) : null}
                <div className='edit-menu-buttons'>
                    <div className='menu-button'>
                        {this.props.currentUser ? <NewCategoryButton /> : null}
                    </div>
                    <div className='menu-button'>
                        {this.props.currentUser ? <EditMenuButton onClick={this.toggleMenuEditable} isEditing={this.state.menuEditable} /> : null}
                    </div>
                </div>
            </div>
        )
    }
}

Your EditMenuButton can now be significantly simpler. You'll need to make two changes: remove the state and instead use the isEditing prop, and pass the onClick prop to the HTML button

class EditMenuButton extends Component {
    render() {
        const { isEditing, onClick } = this.props;

        return (
            <Button onClick={onClick} style={{ backgroundColor: isEditing ? "#b9edee" : "#222222", color: isEditing ? "#000000" : "#ffffff", border: isEditing ? "none" : "1px solid #222222"}}>{isEditing ? "Save Edits" : "Edit Menu" }</Button>
        );
    }
}

Your EditMenuButton now does not have to be concerned about managing state, it just reacts to the props coming into it, which will make it easier to work with (less to think about) and less prone to bugs. You could even simplfy this further by making it a function component.

Create a function to update state in your parent component and pass it to the child component. In your parent component declare:

toggleMenuEditable = () => {
  this.setState({ menuEditable: !this.state.menuEditable });
}

Pass it to the child component as a prop and call it in the changeText function.

Something like this:

changeText = () => {
    const { text } = this.state;
    if(text === "Edit Menu") {
        this.setState({text: "Save Edits"});
        this.props.toggleMenuEditable();

    } else {
        this.setState({text: "Edit Menu"});
    }
}

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