Leo Messi
Leo Messi

Reputation: 6166

How to update a component based on changes in another component in React

There are two components which don't have parent-child or sibling relationship between them.

One of them build the Toolbar and another one contains a color picker. The idea is to change the color of the Toolbar based on the value set in the color picker.

Here is my code so far:

import React from 'react';
import { Button, Icon } from 'semantic-ui-react';
import { ChromePicker } from 'react-color';

export default class Banner extends React.PureComponent {
  constructor(props) {
    super(props);
    this.state = {
      displayColorPicker: false,
      background: '#fff',
    };
  }

  handleClick = () => {
    this.setState({ displayColorPicker: true });
  };

  handleClose = () => {
    this.setState({ displayColorPicker: false });
  };

  handleChange = color => {
    this.setState({ background: color.hex });
  };

  handleChangeComplete = color => {
    this.setState({ background: color.hex });
  };

  render() {
    const popover = {
      position: 'absolute',
      zIndex: '2',
    };
    const cover = {
      position: 'fixed',
      top: '0px',
      right: '0px',
      bottom: '0px',
      left: '0px',
    };
    return (
      <div className="banner-container settings-banner">
        <table className="settings-banner-container">
          <tbody>
            <tr className="setttings-container-tr">
              <div
                className="xx"
                style={{ backgroundColor: this.state.background }}>
                <div className="title-cell-value settings-banner-title">
                  Brand color
                </div>
                <div>
                  <Button onClick={this.handleClick}>Pick Color</Button>
                  {this.state.displayColorPicker ? (
                    <div style={popover}>
                      <div
                        style={cover}
                        onClick={this.handleClose}
                        onKeyDown={this.handleClick}
                        role="button"
                        tabIndex="0"
                        aria-label="Save"
                      />
                      <ChromePicker
                        color={this.state.background}
                        onChange={this.handleChange}
                        onChangeComplete={this.handleChangeComplete}
                      />
                    </div>
                  ) : null}
                </div>
              </div>
            </tr>
          </tbody>
        </table>
      </div>
    );
  }
}

In the above file, the ChromePicker is used to choose a color and save its value in this.state.background. I'm using that value to update the color of div with class xx. This works good, the div's color is updated directly.

However, I don't know how to "export" that color value outside and use it in another component.

In this case it would be the Toolbar, I want to send the value from this.state.background to the style = {{ .. }}

Is there a way to do it?

import React from 'react';
import Logo from '../Logo/Logo';

export default class Toolbar extends React.PureComponent {
  render() {
    return (
      <div className="corporate-toolbar" style={{ backgroundColor: 'green' }}>
        <Logo corporate />
      </div>
    );
  }
}

Upvotes: 0

Views: 1563

Answers (2)

HMR
HMR

Reputation: 39260

Here is a working example using context:

//in file ColorContext.js (should export but breaks snippet)
const ColorContext = React.createContext();
const ColorProvider = ({ children }) => {
  const [color, setColor] = React.useState('#fff');
  return (
    <ColorContext.Provider value={{ color, setColor }}>
      {children}
    </ColorContext.Provider>
  );
};
//in file Banner.js
class Banner extends React.PureComponent {
  handleChange = (color) => {
    this.context.setColor(color);
  };

  render() {
    return (
      <div style={{ backgroundColor: this.context.color }}>
        <select
          value={this.context.color}
          onChange={(e) =>
            this.handleChange(e.target.value)
          }
        >
          <option value="#fff">fff</option>
          <option value="#f00">f00</option>
          <option value="#f0f">f0f</option>
        </select>
      </div>
    );
  }
}
//ColorContext is imported from ColorContext.js
Banner.contextType = ColorContext;
//in file Toolbar.js
class Toolbar extends React.PureComponent {
  render() {
    return (
      <h1 style={{ backgroundColor: this.context.color }}>
        Toolbar
      </h1>
    );
  }
}
//ColorContext is imported from ColorContext.js
Toolbar.contextType = ColorContext;

const App = () => (
  <div>
    <Banner />
    <Toolbar />
  </div>
);
ReactDOM.render(
  <ColorProvider>
    <App />
  </ColorProvider>,
  document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>

Upvotes: 1

Hovakimyan
Hovakimyan

Reputation: 558

There is many ways to do it

You can use context(best solution), redux(if you app is really big) or just move the property to the common parent and pass it to components (it's the worst way, not recommended)

Documentation for context - https://reactjs.org/docs/context.html

Documentation for redux - https://react-redux.js.org

A simple example of using context https://www.digitalocean.com/community/tutorials/react-usecontext

Upvotes: 1

Related Questions