Max Silva
Max Silva

Reputation: 577

Passing state from a child component to another child component contained within a parent component

I have a child functional component 'Display'. Which contains two buttons. The buttons toggle a state between true or false.

I want to pass this boolean value back to the parent container (component).

I then want to pass this boolean value to another child functional component called 'DisplayTitle'. Based on the boolean value I want to just update a string prop that gets rendered in the functional component.

I am slightly new to this. Should I be using redux or is there a more simple way of doing this? Thanks

Haven't yet

'Display' child component:

import * as React from 'react';

import Button from 'react-bootstrap/Button';
import Col from 'react-bootstrap/col';

interface Props {
    buttonOneLabel: string;
    buttonTwoLabel: string;
}

const Display = ({
    buttonOneLabel,
    buttonTwoLabel,
}: Props) => {
    const [state, setVariant] = React.useState({ status: true });

    return (
        <>
            <Col md="auto">
              <Button
              onClick={() => setVariant({ status: true })}
              variant={state.status ? 'primary' : 'outline-primary'}
              >
              {buttonOneLabel}
              </Button>
              <Button
              onClick={() => setVariant({ status: false })}
              variant={state.status ? 'outline-primary' : 'primary'}
              >
              {buttonTwoLabel}
              </Button>
            </Col>
        </>
    );
};

export default Display;

'DisplayTitles' child component:

import * as React from 'react';

import Col from 'react-bootstrap/col';

interface Props {
    title: string;
}

const DisplayTitles = ({
    title,
}: Props) => (
    <>
        <Col>
          <h3>{title}</h3>
        </Col>
    </>
);

export default DisplayTitles;

Parent component

import * as React from 'react';

import Jumbotron from 'react-bootstrap/Jumbotron';
import Container from 'react-bootstrap/Container';
import Row from 'react-bootstrap/row';

import Title from './Title';
import SearchBy from './SearchBy';
import QuickSearch from './QuickSearch';
import Dates from './Dates';
import Display from './Display';
import DisplayTitle from './DisplayTitle';
import RunReport from './RunReport';
import AdvancedSearch from './AdvancedSearch';
import Options from './Options';

const Header = () => (
  <div className="daily-sales-header">
    <Jumbotron>
      <Container fluid>
        <Title
          title="Daily Sales"
          subTitle="(Single Page)"
        />
        <Row>
          <SearchBy
            colClass="search-by-col"
            buttonId="search-by-button"
            buttonLabel="Search by"
          />
          <QuickSearch
            buttonLabel="Quick Search"
            eleClass="quick-search"
            eleIdBtn="quick-search-button"
          />
          <Dates
            fromClass="from-date"
            fromLabel="From"
            toClass="to-date"
            toLabel="To"
          />
          <Display
            buttonOneLabel="Department"
            buttonTwoLabel="Sub-Department"
            onSelectLanguage={handleVari}
          />
          <RunReport
            buttonLabel="Run Report"
          />
        </Row>
        <Row>
          <AdvancedSearch
            buttonClass="adv-search-btn pull-right"
            buttonLabel="Advanced Search"
          />
        </Row>
      </Container>
    </Jumbotron>
    <Row>
      <DisplayTitle
        title="Department Sales"
      />
      <Options />
    </Row>
  </div>
);

export default Header;

Upvotes: 1

Views: 66

Answers (1)

Fyodor Yemelyanenko
Fyodor Yemelyanenko

Reputation: 11848

Lifting state up is the most simple approach here.

Parent component will hold state for all children components and pass 1. Values as props 2. Callbacks so children may change values

Example (not tested, use as hint only)

const Header = () => {
    const [state, setVariant] = React.useState({ status: true });

    return <div className="daily-sales-header">
        /* ... */
        <Display
            uttonOneLabel="Department"
            buttonTwoLabel="Sub-Department"
            onSelectLanguage={handleVari}
            setVariant={setVariant.bind(this)}
            status={state.status}
      />
      /* ... */
  <DisplayTitle
    title="Department Sales"
    status={state.status}
  />
  <Options />
</Row>
</div>
}

Disply component will be

import * as React from 'react';

import Button from 'react-bootstrap/Button';
import Col from 'react-bootstrap/col';

interface Props {
    buttonOneLabel: string;
    buttonTwoLabel: string;
    status: boolean;
    setVariant: (status: {status: boolean}) => void;
}

const Display = ({
    buttonOneLabel,
    buttonTwoLabel,
    status,
    setVariant
}: Props) => {
return (
    <>
        <Col md="auto">
          <Button
          onClick={setVariant.bind(this, { status: true })}
          variant={status ? 'primary' : 'outline-primary'}
          >
          {buttonOneLabel}
          </Button>
          <Button
          onClick={setVariant.bind(this, { status: false })}
          variant={status ? 'outline-primary' : 'primary'}
          >
          {buttonTwoLabel}
          </Button>
        </Col>
    </>
    );
};

export default Display;

Display titles will be

// ...
interface Props {
    title: string;
    status: boolean;
}

const DisplayTitles = ({
    title,
    status
}: Props) => (
    <>
        <Col>
             <h3>{title}</h3>
             <h3>{status}</h3>
        </Col>
    </>
);
// ...

As a result, when you click button in Display component, setVariant from parent component will be called. It updates status in parent which will be immedeately propagated as props to both Display and DisplayTitles

Upvotes: 1

Related Questions