How to make a react component that can be controled from outside? - javascript

I'm trying to make a Dialog component using React and Material-UI.
For now, I have the traditional behavior of the Material-UI dialog with a button inside the class that can open the dialog. But the behavior that i want for this component is the same that the Material-UI dialog have.
So I want to change his state and re-render the component calling it like this:
var open = false;
<AuthDialog open={open} />
And using an outside button that change the open variable to true.
This is my Code:
class AuthDialog extends React.Component {
constructor(props, context){
super(props, context);
this.state = {
open: false,
};
};
handleRequestOpen = () => {
this.setState({
open: true,
});
};
handleRequestClose = () => {
this.setState({
open: false,
});
};
render() {
return (
<div>
<RaisedButton children="login" onTouchTap={ this.handleRequestOpen } />
<Dialog open={this.state.open} onRequestClose={this.handleRequestClose}>
// Content
</Dialog>
</div>
);
}
}
I'm a beginer with JS, so if my code isn't right somewhere I will appreciate some comments too.
Edit: This is my code now after the modification:
class AuthDialog extends React.Component {
constructor(props, context){
super(props, context);
this.state = {
// State of authBody
};
};
render() {
const { onRequestClose, open } = this.props;
return (
<Dialog open={open} onRequestClose={onRequestClose}>
// Body of the dialog
</Dialog>
);
}
}
And in the parent:
closeAuthDialog = () => {
this.setState({
openAuthDialog: false,
});
}
openAuthDialog = () => {
this.setState({
openAuthDialog: true,
});
}
<RaisedButton children="login" onTouchTap={ this.openAuthDialog } />
<AuthDialog open={this.state.openAuthDialog} onRequestClose={this.closeAuthDialog} handleLoginSuccess={ this.handleLoginSuccess } />

In order to achieve that, you need to use the props instead of the local state.
class AuthDialog extends React.PureComponent {
static propTypes = {
open: React.PropTypes.bool.isRequired,
onClose: React.PropTypes.func.isRequired,
onOpen: React.PropTypes.func.isRequired,
};
render() {
const { onClose, onOpen, open } = this.props;
return (
<div>
<RaisedButton children="login" onTouchTap={onOpen} />
<Dialog open={open} onRequestClose={onClose}>
// Content
</Dialog>
</div>
);
}
}
and then from the parent class you need to send the two function and the open prop.
<AuthDialog open={open} onOpen={this.toggleOpenToTrue} onClose={this.toggleOpenToFalse} />

Just get attributes you pass from this.props like this:
...
render() {
const { open, onRaisedButtonClick } = this.props;
return (
<div>
<RaisedButton children="login" onTouchTap={ onRaisedButtonClick } />
<Dialog open={open} onRequestClose={this.handleRequestClose}>
// Content
</Dialog>
</div>
);
}
...
Also, when you have stateless component with no lifecycle methods, you can use functional component; it's much simpler and readable:
const AuthDialog = ({ open, onRaisedButtonClick }) => (
<RaisedButton children="login" onTouchTap={ onRaisedButtonClick } />
<Dialog open={open} onRequestClose={this.handleRequestClose}>
// Content
</Dialog>
)

I am not sure what you're exactly looking for. But from what I have understood, you want to use your AuthDialog component like this;
<AuthDialog open={open} />
And when the <RaisedButton/> is clicked, you need to show the <Dialog /> and also to change the 'open' state/var on the parent as well.
In this case you're gonna wanna go for Flux or Redux to manage your app state. Since two-way binding in React is a bad practice that will be your best shot at achieving this.

Related

I have my modal component in a different file and I'm trying to open it from another component

BuySectionItem.js
class BuySectionItem extends React.PureComponent {
constructor( props ) {
super( props );
this.state = {
modalIsOpen: false,
}
this.toggleTicketModal = this.toggleTicketModal.bind( this );
}
toggleTicketModal = () => {
this.setState( { modalIsOpen: ! this.state.modalIsOpen } );
}
componentDidMount() {
// this.setActivePrice();
}
outputBuyButton( offer ) {
// Universe ID override is present.
return <Button text="Buy Ticket" type="green-gradient" onClick={ this.toggleTicketModal }/>
return null;
}
render() {
<div>
{this.state.modalIsOpen &&
<TicketModal isOpen={this.state.modalIsOpen} toggleTicketModal={ this.toggleTicketModal } />
}
</div>;
}
}
export default BuySectionItem;
TicketModal.js
import React from 'react';
import Modal from 'react-modal';
import PropTypes from 'prop-types';
const customStyles = {
content: {
top: '50%',
left: '50%',
right: 'auto',
bottom: 'auto',
marginRight: '-50%',
transform: 'translate(-50%, -50%)',
},
};
Modal.setAppElement( 'body' )
class TicketModal extends React.Component {
componentDidMount() {
this.handleKeyEvents();
}
componentWillUnmount() {
this.removeKeyHandler();
}
/**
* Watch for the escape key when the modal is open to allow users to escape from the modal.
*/
handleKeyEvents() {
const handleKeyDown = event => {
if ( event.keyCode === 27 ) {
this.props.toggleTicketModal( event );
}
};
/*
* Attach our event listener to the window.
*/
window.addEventListener( 'keydown', handleKeyDown );
/*
* Cancel the key event handling, and remove
*/
this.removeKeyHandler = () => {
window.removeEventListener( 'keydown', handleKeyDown );
};
}
render() {
const {
isOpen,
// pending,
toggleTicketModal,
} = this.props;
return (
<Modal
isOpen={isOpen}
onRequestClose={toggleTicketModal()}
style={customStyles}
contentLabel="Meal Modal"
>
<div className="modal-wrapper">
<div className="container text-center">
<h1>Hello</h1>
<h2>ID of this modal is 100</h2>
<h3>This is an awesome modal.</h3>
<button onClick={toggleTicketModal()}>close</button>
</div>
</div>
</Modal>
)
}
}
TicketModal.propTypes = {
pending: PropTypes.bool,
toggleTicketModal: PropTypes.func,
isOpen: PropTypes.bool,
};
export default TicketModal;
As you can see I am trying to open the ticket modal component from the `buysectionitem` component on a button Click.
But for some reason the Modal doesn't seem to be opening.
When I kept a break point I see that the `togglemodal` function is being called but doesn't open at all.
I added some more code as I need guidance with the handle key events as well. This key event which was supposed to remove the modal from the screen when I click escape which doesn't seem to be working.
Optimized code
class BuySectionItem extends React.Component {
constructor() {
super();
this.state = {
showModal: false
};
}
handleOpenClose = () => {
this.setState(prev => ({ showModal: !prev.showModal }));
};
render() {
return (
<div>
<button onClick={this.handleOpenClose}>Trigger Modal</button>
<Modal
isOpen={this.state.showModal}
contentLabel="Minimal Modal Example"
>
<TicketModal handleOpenClose={this.handleOpenClose} />
</Modal>
</div>
);
}
}
class TicketModal extends React.Component {
render() {
const { handleOpenClose } = this.props;
return (
<div>
<button onClick={handleOpenClose}>Close Modal</button>
<hr />
<p>Welcome to opened model</p>
</div>
);
}
}
Live demo
you are calling the toggleTicketModal function when the TicketModal renders,call it like this
<button onClick={()=>toggleTicketModal()}>close</button>
this will do.
there are many mistakes in your code.
button onclick handler in modal should be like following,
<button onClick={toggleTicketModal}>close</button>
also you don't have to do same handling while closing the modal, following is redundant inside Modal props
onRequestClose={toggleTicketModal}
also main container in your case BuySectionItem.js has few issues.
1.there is no return in render method.
2.conditional rendering is not done correctly, you are never calling outPutBuyButton based on modalIsOpen state
3. you have used name "isModalOpen" instead of "modalIsOPen" , bad typo.
here's working code. modify as per your needs.
https://codesandbox.io/s/gracious-hopper-vmerd

Passing a variable between non-nested components using Context API

Suppose I have two components which aren't nested: a button and a panel. When the button is clicked, the panel will show or hide depending on the previous state (like an on/off switch). They aren't nested components, so the structure looks like this:
<div>
<Toolbar>
<Button />
</Toolbar>
<Content>
...
<ButtonPanel />
</Content>
</div>
I can't change the structure of the DOM. I also can't modify any other component other than the button and panel components.
The Button and ButtonPanel components are related, however, and will be used together throughout the solution. I need to pass a property to the panel to let it know when to show or when to hide. I was thinking about doing it with Context API, but I think there's something I'm doing wrong and the property never updates.
This is my code:
Context
import React from 'react';
export const ButtonContext = React.createContext({
showPanel: false,
});
Button
import React, { Component } from 'react';
import { ButtonContext } from './ButtonContext';
class Button extends Component {
constructor() {
super();
this.state = {
showPanel: false,
};
}
render() {
return (
<ButtonContext.Provider value={{ showPanel: this.state.showPanel }}>
<li>
<a
onClick={() => this.setState({ showPanel: !this.state.showPanel }, () => console.log('Changed'))}
>
<span>Button</span>
</a>
</li>
</ButtonContext.Provider>
);
}
}
export { Button };
Panel
import React, { Component } from 'react';
import { Panel, ListGroup, ListGroupItem } from 'react-bootstrap';
import { ButtonContext } from './ButtonContext';
class ButtonPanel extends Component {
static contextType = ButtonContext;
render() {
return (
<ButtonContext.Consumer>
{
({ showPanel }) => {
if (showPanel) {
return (
<Panel id="tasksPanel">
<Panel.Heading >Panel Heading</Panel.Heading>
<ListGroup>
<ListGroupItem>No Items.</ListGroupItem>
</ListGroup>
</Panel>
);
}
return null;
}
}
</ButtonContext.Consumer>
);
}
}
export { ButtonPanel };
I've also tried simply accessing the context in the ButtonPanel component like so:
render() {
const context = this.context;
return context.showPanel ?
(
<Panel id="tasksPanel">
<Panel.Heading >Tasks</Panel.Heading>
<ListGroup>
<ListGroupItem className="tasks-empty-state">No tasks available.</ListGroupItem>
</ListGroup>
</Panel>
)
:
null;
}
What am I doing wrong?
Thanks
From the React docs:
Accepts a value prop to be passed to consuming components that are descendants of this Provider.
So this means that <ButtonContext.Provider> has to wrap <ButtonContext.Consumer> or it has to be higher up in the component hierarchy.
So based on your use case, you could do:
// This app component is the div that wraps both Toolbar and Content. You can name it as you want
class App extends Component {
state = {
showPanel: false,
}
handleTogglePanel = () => this.setState(prevState => ({ togglePanel: !prevState.togglePanel }));
render() {
return (
<ButtonContext.Provider value={{ showPanel: this.state.showPanel, handleTogglePanel: this.handleTogglePanel }}>
<Toolbar>
<Button />
</Toolbar>
<Content>
<ButtonPanel />
</Content>
</ButtonContext.Provider>
);
}
}
class Button extends Component {
...
<ButtonContext.Consumer>
{({ handleTogglePanel }) => <a onClick={handleTogglePanel} />}
</ButtonContext.Consumer>
}
class ButtonPanel extends Component {
...
<ButtonContext.Consumer>
{({ showPanel }) => showPanel && <Panel>...</Panel>}
</ButtonContext.Consumer>
}

Calling Child component function from Parent component in React.js

I am trying to call a function in my child component from a button click event in my parent component.
Parent Component:
class Parent extends Component{
constructor(props){
super(props);
this.state = {
//..
}
}
handleSaveDialog = (handleSaveClick) => {
this.handleSaveClick = handleSaveClick;
}
render(){
return(
<div>
<Button onClick={this.openDialog}>Open Dialog</Button>
<Dialog>
<DialogTitle id="form-dialog-title">Child Dialog</DialogTitle>
<DialogContent>
<Child handleSaveData={this.handleSaveDialog}/>
</DialogContent>
<DialogActions>
<Button onClick={this.handleSaveClick} color="primary">
Save
</Button>
</DialogActions>
</Dialog>
</div>
);
}
}
In the above code, the Parent component renders a Child component modal dialog (based on Material-UI) on click of a button. The Save button, part of the Dialog component in Parent, when clicked should call a save function in the Child component. As you can see, I have passed a callback function handleSaveDialog through the Childcomponent props named handleSaveData. The save button click will call handleSaveClick on the child, once the Child component mounts and passes the callback to the Parent component.
Child Component:
class Child extends Component{
constructor(props){
super(props);
this.state = {
//..
}
}
componentDidMount(){
console.log('mount');
this.props.handleSaveData( () => this.handleSaveClick());
}
handleSaveClick = () => {
console.log('save clicked');
}
render(){
return(
<div>
//..
</div>
);
}
}
In the above code, I am using the accessing the callback function passed by the Parent component props and binding it to the Child component's save fucntion handleSaveClick.
Problem:
When I click the Open Dialog button in Parent, for the first time, the Dialog mounts the Child component. However, the click on Save button does not work (no error). After, closing the dialog, when I reopen the Dialog and click on Save, the handleSaveClick in the Child dialog is triggered and a message is logged in the browser console. Any idea why this works on the second time and not the first time?
Remember, the Child Component is mounted/loaded only when I click the Open Dialog on the Parent component.
References:
https://material-ui.com/components/dialogs/#form-dialogs
Call child method from parent
https://github.com/kriasoft/react-starter-kit/issues/909#issuecomment-390556015
It will not work because if you console log this.handleSaveClick in render function it will be undefined as there is no re-render. So there are 2 ways to go for this:
Saving function in the state. Link: https://codesandbox.io/s/fervent-browser-gw75c
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {
open: false
};
}
openDialog = () => {
this.setState(preState => ({
open: !preState.open
}));
};
handleSaveDialog = handleSaveRef => {
this.setState({
handleSaveClick: handleSaveRef
});
};
render() {
console.log("Render", this.handleSaveClick);
return (
<div>
<Button onClick={this.openDialog}>Open Dialog</Button>
<Dialog open={this.state.open}>
<DialogTitle id="form-dialog-title">Child Dialog</DialogTitle>
<DialogContent>
<Child handleSaveData={this.handleSaveDialog} />
</DialogContent>
<DialogActions>
<Button onClick={this.state.handleSaveClick} color="primary">
Save
</Button>
</DialogActions>
</Dialog>
</div>
);
}
class Child extends Component {
componentDidMount() {
console.log("mount");
this.props.handleSaveData(this.handleSaveClick);
}
handleSaveClick = () => {
console.log("save clicked");
};
render() {
return <div>//..</div>;
}
}
Using ref. Link: https://codesandbox.io/s/musing-kalam-nj29n
const childRef = React.createRef();
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {
open: false
};
}
openDialog = () => {
this.setState(preState => ({
open: !preState.open
}));
};
handleSaveClick = () => {
if (childRef.current) {
childRef.current.handleSaveClick();
}
};
render() {
return (
<div>
<Button onClick={this.openDialog}>Open Dialog</Button>
<Dialog open={this.state.open}>
<DialogTitle id="form-dialog-title">Child Dialog</DialogTitle>
<DialogContent>
<Child ref={childRef} />
</DialogContent>
<DialogActions>
<Button onClick={this.handleSaveClick} color="primary">
Save
</Button>
</DialogActions>
</Dialog>
</div>
);
}
}
class Child extends Component {
handleSaveClick = () => {
console.log("save clicked");
};
render() {
return <div>//..</div>;
}
}
Using callback to save instance and than use arrow function:
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {
open: false
};
}
openDialog = () => {
this.setState(preState => ({
open: !preState.open
}));
};
handleSaveDialog = handleSaveRef => {
this.handleSaveClick = handleSaveRef;
};
render() {
return (
<div>
<Button onClick={this.openDialog}>Open Dialog</Button>
<Dialog open={this.state.open}>
<DialogTitle id="form-dialog-title">Child Dialog</DialogTitle>
<DialogContent>
<Child handleSaveData={this.handleSaveDialog} />
</DialogContent>
<DialogActions>
<Button onClick={() => this.handleSaveClick()} color="primary">
Save
</Button>
</DialogActions>
</Dialog>
</div>
);
}
}
class Child extends Component {
componentDidMount() {
console.log("mount");
this.props.handleSaveData(this.handleSaveClick);
}
handleSaveClick = () => {
console.log("save clicked");
};
render() {
return <div>//..</div>;
}
}
You will need to use arrow function in onClick as it will create a new function every time we click and thus getting a new instance of handleClick. And if you pass this.handleClick it won't work because it is undefined. You can check this by logging the value of this.handleClick in render function.
Note: Use the 2 option its more reliable.
Hope this helps!
Well, I don't know why you have this sort of scenario but the first things that comes in my mind is that you can write handleSaveClick method in your Parent component. And in case you need to use that function on any action that might be happening in your child component, you can pass this function as a prop from parent component. So your both cases can be handled
You can call this method on something happening in parent component
You can use the same method on any action that is happening in your child component.
If still you think that you have to define the method in your child component, you can use the refs

setState() does not change state when called from element that depends on state to render

I have a little component like this (Code below is simplified to the parts needed) that behaves very strange when it comes to updating the state.
class Componenent extends React.Component {
constructor(props) {
super(props);
this.state = {showStuff: false};
}
render() {
return(
//Markup
{this.state.showStuff && (
<button onClick={() => this.setState({showStuff: false})} />
)}
// More Markup
);
}
}
The state gets updated somewhere else in the component, so the prop is true when the button is clicked.
A click also triggers the setState function (callback gets executed), however the state does not update.
My guess is that it does not update because the function is called by an element that directly depends on the state prop to be visible.
I figured out that adding another prop test: true to the state and changing that property to false when the button is clicked also triggers the showStuff prop to change to false. So it works when I make strange hacks.
Can someone explain this weird behavior to me? I can't gasp why the above snippet does not work like intended.
Here is the entire component:
class ElementAdd extends React.Component {
constructor(props) {
super(props);
this.defaultState = {
showElementWheel: false,
test: true
};
this.state = this.defaultState;
}
handleAddCardClick() {
if (this.props.onCardAdd) {
this.props.onCardAdd({
type: ElementTypes.card,
position: this.props.index
});
}
}
handleAddKnowledgeClick() {
if (this.props.onCardAdd) {
this.props.onCardAdd({
type: ElementTypes.knowledge,
position: this.props.index
});
}
}
handleTabPress(e) {
if (e.key === 'Tab') {
e.preventDefault();
let target = null;
if (e.shiftKey) {
if (e.target.previousSibling) {
target = e.target.previousSibling;
} else {
target = e.target.nextSibling;
}
} else {
if (e.target.nextSibling) {
target = e.target.nextSibling;
} else {
target = e.target.previousSibling;
}
}
target.focus();
}
}
hideElementWheel() {
// This is somehow the only option to trigger the showElementWheel
this.setState({ test: false });
}
render() {
return (
<div
className="element-add"
style={{ opacity: this.props.invisible ? 0 : 1 }}
onClick={() => this.setState(prevSate => ({ showElementWheel: !prevSate.showElementWheel }))}
>
<PlusIcon className="element-add__icon" />
{this.state.showElementWheel && (
<React.Fragment>
<div className="element-add__wheel">
<button
autoFocus
className="element-add__circle"
onClick={this.handleAddCardClick.bind(this)}
onKeyDown={this.handleTabPress.bind(this)}
title="New element"
>
<ViewModuleIcon className="element-add__element-icon" />
</button>
<button
className="element-add__circle"
onClick={this.handleAddKnowledgeClick.bind(this)}
onKeyDown={this.handleTabPress.bind(this)}
title="New knowledge-element"
>
<FileIcon className="element-add__element-icon" />
</button>
</div>
<div
className="element-add__close-layer"
onClick={() => {
this.hideElementWheel();
}}
/>
</React.Fragment>
)}
</div>
);
}
}
By writing onClick={this.setState({showStuff: false})} you are actually calling setState as soon as your button is rendered.
You want to give a function reference to onClick, not call it immediately on render.
<button onClick={() => this.setState({showStuff: false})} />
If your button is inside another element with a click listener that you don't want to run on the same click, you must make sure that the click event doesn't propagate to the parent.
<button
onClick={(event) => {
event.stopPropagation();
this.setState({showStuff: false});
}}
/>
Actually the onClick prop expects a function, you are already providing a function call, so the setState will be called each time the component is rendered, not when clicked.
Try this:
<button onClick={() => this.setState({showStuff: false})} />
Should behave as you expect :)
Works perfectly fine when I update showStuff true (see updated code below.). My guess is the code that is supposed to set showStuff: true is not working. I also added some text in the button.
import React from 'react'
import ReactDOM from 'react-dom'
class Componenent extends React.Component {
constructor(props) {
super(props);
this.state = {showStuff: true};
}
render() {
return(
<div>
{this.state.showStuff && (
<button onClick={() => this.setState({showStuff: false})} > This is a button</button>
)}
</div>
);
}
}
ReactDOM.render(<Componenent />,
document.getElementById('root')
);
Before clicking
After clicking

React how to track event through components

I need ideas about how to solve the following problem in Reactjs:
TextEditor -> Toolbar -> PickColorBox
I have component's relationship (parent -> children) as those listed above.
The problem: The component Toolbar has the state showPickColorBox: false that represents whether the component PickColorBox is visible or not. This state is fired by a button's click event. What I need is the button be capable of toggle the boolean value to the correct state, that is, true if the component is visible, false if it's not. But every time the button event is fired the Toolbar's constructor is called and the state showPickColorBox is set to false, even if the PickColorBox component is visible.
My solution: What I need is to track whether the component PickColorBox is visible or not to set the state to the proper value. Reading some codes I saw examples where a class is instantiated in the root component to keep tracking the events. I try to reproduce the example but it didn't work, I wasn't able to passing as props the function inside the class. I'm even not sure whether it's possible to instantiated a class in javascript, so I need some guide here.
Any help on how to solve, any other solution to this is really appreciated!
I change the code bellow to simplify, so typos in the code isn't the problem, unless is about the instantiated class and how to do it. Another thing, just to clarify the code, I'm using Draftjs framework where the component Editor, the states EditorState and onChange are inheritance.
Root component
export default class TextEditor extends React.Component {
constructor(props) {
super(props);
this.state = {
editorState: EditorState.createEmpty(),
};
this.onChange = (editorState) => this.setState({editorState});
this.modalHandler = new ModalHandler();
}
render() {
const {editorState} = this.state;
return (
<div className={'editor-root'} >
<div className={'editor-toolbar'}>
<Toolbar
editorState={editorState}
onChange={this.onChange}
modalHandler={this.modalHandler}
/>
</div>
<div className={'editor-textarea'} >
<Editor
editorState={editorState}
onChange={this.onChange}
/>
</div>
</div>
);
}
}
ModalHandler class
export default class ModalHandler {
let boolShowComponent = false;
toogleShowComponent = (): boolean => {
return !boolShowComponent;
};
}
Toolbar Component
export default class Toolbar extends React.Component {
constructor(props) {
super(props);
this.state = {
showPickColorBox: false
};
}
_onPickColorClick() {
let bool = this.props.modalHandler.toogleShowComponent()
this.setState({
showPickColorBox: bool,
});
}
render() {
return (
<div className={'ToolbarEditor'} >
{this._onPickColorClick.bind(this)}>PickColor</button>
{
this.state.showPickColorBox ?
<PickColorBox
editorState={this.props.editorState}
onChange={this.props.onChange}
/> :
null
}
</div>
);
}
}
Instead of handling Toolbar using showPickColorBox, try to define the same in TextEditor and pass it as props. Now, to update showPickColorBox, define a method in TextEditor and pass it as props.
export default class TextEditor extends React.Component {
constructor(props) {
super(props);
this.state = {
editorState: EditorState.createEmpty(),
//define here
showPickColorBox: false
};
this.onChange = (editorState) => this.setState({editorState});
this.modalHandler = new ModalHandler();
}
//definehere
_onPickColorClick(bool) {
this.setState({
showPickColorBox: bool,
});
}
render() {
const {editorState} = this.state;
return (
<div className={'editor-root'} >
<div className={'editor-toolbar'}>
<Toolbar
editorState={editorState}
onChange={this.onChange}
modalHandler={this.modalHandler}
//pass here
_onPickColorClick={this._onPickColorClick}
/>
</div>
<div className={'editor-textarea'} >
<Editor
editorState={editorState}
onChange={this.onChange}
/>
</div>
</div>
);
}
}
Now call from toolbar:
export default class Toolbar extends React.Component {
constructor(props) {
super(props);
}
_onPickColorClick() {
let bool = this.props.modalHandler.toogleShowComponent();
//use here
this.props._onPickColorClick(bool);
}
render() {
return (
<div className={'ToolbarEditor'} >
{this._onPickColorClick.bind(this)}>PickColor</button>
{
this.state.showPickColorBox ?
<PickColorBox
editorState={this.props.editorState}
onChange={this.props.onChange}
/> :
null
}
</div>
);
}
}
I find the solution to what I was looking for. It happens that I forgot to createing a properly EventHandler class to track the events fired in children component. So here is the solution:
Root component
export default class TextEditor extends React.Component {
constructor(props) {
super(props);
this.state = {
editorState: EditorState.createEmpty(),
};
this.onChange = (editorState) => this.setState({editorState});
/* this name makes more sense instead of modalHandler */
this.toolbarEventHandler = new ToolbarEventHandler();
}
render() {
const {editorState} = this.state;
return (
<div className={'editor-root'} >
<div className={'editor-toolbar'}>
<Toolbar
editorState={editorState}
onChange={this.onChange}
toolbarEventHandler={this.toolbarEventHandler}
/>
</div>
<div className={'editor-textarea'} >
<Editor
editorState={editorState}
onChange={this.onChange}
/>
</div>
</div>
);
}
}
ToolbarEventHandler (ModalHandler)
/*I will change this class to hold more than one event */
/* Probably change to an array */
export default class ToolbarEventHandler {
constructor() {
this.boolShowComponent = false;
}
get boolShowComponent() {
return this.boolShowComponent;
}
set boolShowComponent(bool){
this.boolShowComponent = bool;
}
}
Toolbar
export default class Toolbar extends React.Component {
constructor(props) {
super(props);
this.state = {
showPickColorBox: false
};
}
_onPickColorClick() {
this.props.toolbarEventHandler.boolShowComponent = !this.props.toolbarEventHandler.boolShowComponent;
this.setState({
showComponent: this.props.toolbarEventHandler.boolShowComponent,
});
}
render() {
return (
<div className={'ToolbarEditor'} >
{this._onPickColorClick.bind(this)}>PickColor</button>
{
this.state.showPickColorBox ?
<PickColorBox
editorState={this.props.editorState}
onChange={this.props.onChange}
/> :
null
}
</div>
);
}
}

Categories

Resources