0
votes

I have written code, which uses a Modal dialog to display a form. My react app is rendered at "root"

index.html

<div id="root"></div>

App.js

const store = configureStore();

    ReactDOM.render(
      <Provider store={store}>
            <ExampleBasic/>
      </Provider>
      , document.getElementById('root'));

ExmpleBasic.js

Please ignore state management in component here. this is just for example.

import React, { PureComponent } from 'react';
import Lorem from 'react-lorem-component';
import Modal from '@atlaskit/modal-dialog';
import Button from '@atlaskit/button';

export default class ExampleBasic extends PureComponent {
  state = { isOpen: false }
  open = () => this.setState({ isOpen: true })
  close = () => this.setState({ isOpen: false })
  secondaryAction = ({ target }) => console.log(target.innerText)

  render() {
    const { isOpen } = this.state;
    const actions = [
      { text: 'Close', onClick: this.close },
      { text: 'Secondary Action', onClick: this.secondaryAction },
    ];

    return (
      <div>
        <Button onClick={this.open}>Open Modal</Button>

        {isOpen && (
          <Modal
            actions={actions}
            onClose={this.close}
            heading="Modal Title"
          >
            <BasicFormContainer />
          </Modal>
        )}
      </div>
    );
  }
}

BasicFormContainer.js

const mapStateToProps = state => ({
  addDesignation: state.designations.addDesignation,
});

const mapDispatchToProps = dispatch => ({
});

export default connect(mapStateToProps, mapDispatchToProps)(BasicForm);

BasicForm.js

import React, { Component } from 'react';
import { Field, reduxForm } from 'redux-form';

class BasicForm extends Component {
  constructor(props) {
    super(props);
    this.submit = this.submit.bind(this);
  }

  submit(values) {
    console.log(values);
  }

  render() {
    const { handleSubmit } = this.props;

    return (

      <form onSubmit={handleSubmit(this.submit)}>
        <Field
          name="designationName"
          component="input"
          placeholder="Name"
          label="Enter name"
          autoFocus
        />
      </form>

    );
  }
}


export default reduxForm({
  form: 'BasicForm',
  enableReinitialize: true,
})(BasicForm);

However modal is rendered using portal, outside current DOM.

As modal is rendered outside the scope of redux context, it is not getting the store. and i am getting an error "Uncaught Error: Field must be inside a component decorated with reduxForm()"

Below is link to same kind of problem, where redux form within portal is not working. Redux Form Wrapped Inside Custom Portal Component?

3

3 Answers

1
votes

in React 16 it is handled by portals, but version before then that you can try something like as follow.

export default class ExampleBasic extends PureComponent {
  ...

  static contextTypes = { store: React.PropTypes.object };
  render() {
    const { isOpen } = this.state;
    const actions = [
      { text: 'Close', onClick: this.close },
      { text: 'Secondary Action', onClick: this.secondaryAction },
    ];

    return (
      <div>
        <Button onClick={this.open}>Open Modal</Button>

        {isOpen && (
          <Modal
            actions={actions}
            onClose={this.close}
            heading="Modal Title"
          >
            <Provider store={this.context.store}>
               <BasicFormContainer />
            </Provider>
          </Modal>
        )}
      </div>
    );
    }
  }
0
votes

You need to pass in the values of BasicForm.js to the Redux store and dispatch an action from there itself and not from the BasicFormContainer.js. This way, the Modal remains inside of the scope of your root element and thus there is no need to access the store outside of the Provider.

Then update the Redux store based on the values entered in the form. Once, the store is updated, you can then access it from anywhere in your application such as Modal in your case.

0
votes

I downgraded to version 2.1.0 to solve the problem.