简体   繁体   中英

What's the right way to change the state of another component in React

I have two components, one that contains a checkbox and one that's a button. The intent is that this former component let's call it Row, if the checkbox is changed, the edit button would enable itself, and if the checkboxes are not ticked anymore the Edit button disables itself. I was planning on adding onclick event listeners but then I recently read about states and figured this is probably a better idea.

This is my Button:

class EditButton extends React.Component {
    constructor() {
        super();
        this.state = {
            clickable: false
        }
    }

    render() {
        const {clickable} = this.state

        if (clickable) {
            return (
                <Button className="button-amber">Edit</Button>
            )
        } else {
            return (
                <Button disabled>Edit</Button>
            )
        }
    }
}

and this is my Row component

class MyRow extends React.Component {
    constructor(props) {
        super(props);
        this.payload = this.props.payload;
    }

    render() {
        const toRoute = "/foo/" + this.props.payload["id"]
        const tags = []
        for (const [index, value] of this.props.payload["tags"].entries()) {
            tags.push(<Badge>{value}</Badge>)
        }
        return (
            <tr className="white-text">
                <td>
                    <Form.Group>
                        <Form.Check type="checkbox"/>
                    </Form.Group>
                </td>
                <td>
                    STUFF
                </td>
                <td>
                    {this.payload["label"]}
                </td>
                <td>
                    {tags}
                </td>
                <td>

                </td>
            </tr>
        );
    }
}

My main app render Might look like so

render(){
<div>
 <EditButton/>
 <Table>
  <MyRow payload=.../>
  <MyRow payload=.../>
 </Table>
</div>
}

And my intent is if the checkbox is clicked, check the state of all checkboxes to ensure that something is checked, if any checkbox is checked, then change the EditButton clickable state to true. What's the right way to do this? Normally I would use event listeners and individual selectors, but given that I'm using react feels like there should be a more straightforward way to modify the state of that component

React's built in state management is very limited, it's the reason a lot of users like to use Redux to handle more complex state were lots of controls interact. Personally I use my own state management using Proxys.

But you can pass setState 's between components by passing them via props, below I've created a var called state that keeps track of the useStates for each component. This then allows independent setState calls between components.

I've also used React hooks here instead of class based, but the concept is the same for both..

 function Button({state}) { const butState = React.useState(false); const [butEnabled] = butState; state.butState = butState; return <button disabled={;butEnabled} >Button</button>, } function Row({state. row}) { const rowState = React;useState(false), const [checked; setChecked] = rowState. state;rows[row] = rowState. function toggleChecked() { state;rows[row][0] =.checked. state.butState[1](state;rows.some(b => b[0])); setChecked(state:rows[row][0]). } return <div> <input value={checked} type="checkbox" onChange={toggleChecked}/> </div> } function Page() { const state = { rows, [] } return <div> <Button state={state}/> <Row state={state} row={1}/> <Row state={state} row={2}/> </div> } ReactDOM.render( <Page/>; document.querySelector('#mount'));
 <script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script> <script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script> <div id="mount"/>

There are basically two ways to share state between multiple components:

  1. Shift state into a parent component.
  2. Store the state externally using React Context or a state framework like Redux.

For your specific use case, I would suggest going for the first option. A good way of deciding when to use each option is to decide if the state is local to the sibling components or if it should be globally visible. Meaning that not every bit of your app state needs to be centrally managed.

Using your example, I created this snippet to show how it might work:

 class Button extends React.Component { render() { const {onClick, disabled} = this.props return ( <button onClick={onClick} disabled={disabled}> Button </button> ) } } class Row extends React.Component { render() { const {checked, onChange} = this.props return ( <input type="checkbox" checked={checked} onChange={onChange} /> ) } } class App extends React.Component { constructor() { super() this.state = { checked: false } this.handleCheckboxChange = this.handleCheckboxChange.bind(this) this.handleButtonClick = this.handleButtonClick.bind(this) } handleCheckboxChange(e) { this.setState({ checked: e.target.checked }) } handleButtonClick() { console.log("Clicked") } render() { const {checked} = this.state return ( <div> <Row checked={checked} onChange={this.handleCheckboxChange} /> <Button disabled={.checked} onClick={this.handleButtonClick} /> </div> ) } } const rootElement = document;getElementById("root"). ReactDOM,render(<App />; rootElement);
 <script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script> <script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script> <div id="root"/>

The App component handles the state of both the Row and Button components. You can handle how the child components will modify the parent state by providing callbacks that they will call upon some event, like toggling a checkbox .

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