9

I have a simple component which is supposed to render different kind of fields into my form component:

import React from "react";

export default class Field extends React.Component {

  render() {
    switch (this.props.type) {
      case 'textarea': {
        return (
          <div className="col-xs-12">
            <textarea
              placeholder={this.props.placeholder}
              name={this.props.name}
            >
            </textarea>
          </div>
          )
      }
      case 'text': {
        return (
          <div className="col-md-6 col-lg-4">
            <input
              type="text"
              placeholder={this.props.placeholder}
              name={this.props.name}
            />
          </div>
        )
      }
    }
  }
}

And I'm using this component in my form component like this:

export default class SubmitForm extends React.Component {

  render() {
    return (
        .
        .
        .
        <Field
          type="text"
          placeholder="something"
          name="something"
        />
        <Field
          type="textarea"
          placeholder="another"
          name="othername"
        />
        .
        .
        .
    )
  }
}

What I have in mind is to somehow implement my field component to be able to use dot notation as explained in Using Dot Notation for JSX components which I have seen many other libraries and I want to be able to use this component like this:

<Field.Text name="sth" placeholder="sth" />
<Field.TextArea name="other" placeholder="other stuff" /> 

But I can't do it the way mentioned in React docs. How can I do this?

Andrew Li
  • 55,805
  • 14
  • 125
  • 143
Taxellool
  • 4,063
  • 4
  • 21
  • 38

3 Answers3

18

Just create individual components and export them under names:

//Field.js
class TextArea extends React.Component {
  ...
}

class Text extends React.Component {
  ...
}

export { Text, TextArea };

Then import all the names from the module:

import * as Field from './path/to/Field.js';

Or if you prefer exporting a default object like so (which is exactly what the example from the documentation is doing, just in a different way):

export default { Text, TextArea };

Which will use object shorthand properties and export a default member -- an object literal. Then you can import it like so:

import Field from './path/to/Field.js';

And finally:

<Field.TextArea ... />

Or, to get rid of dot notation (you can't do this with the default export option!):

import { Text, TextArea } from './path/to/Field.js';

<Text ... />
<TextArea ... />

Of course, going exactly by the React documentation, you could do, with class expressions:

const Field = {
  Text: class Text extends React.Component { //you can omit the class name here
    //can be stateless functional component if you don't need state
  },
  TextArea: class TextArea extends React.Component {

  }
}

export default Field;

Then importing as a default member and using dot notation.

Andrew Li
  • 55,805
  • 14
  • 125
  • 143
  • so actually there is no point in achieving this dot notation I guess. and i should create separate components anyway. and find a way to share mutual event handlers and other stuff between these components. Is this the only way? I mean I've seen other libraries like react-redux-form which provides something like or . are they also doing so with just exporting under name of Control? – Taxellool Jul 05 '17 at 04:23
  • @Taxellool Well, it's mostly for organizational purposes. They just have a namespace such as `Field` to group all their field type components together, and exporting the namespace. – Andrew Li Jul 05 '17 at 04:24
  • thanks. the final section of your answer actually made me understand the way explained in docs. Anyway right now I don't see a reason to pursue this anymore. the whole purpose of "dot notation" seems to be for organizing as u said. And separate components must be defined either way. thanks for your answer. – Taxellool Jul 05 '17 at 04:38
2

Simply following the docs.

const Field = {
  Text: function Text(props) {
    return <div className="col-md-6 col-lg-4">
            <input
              type="text"
              placeholder={this.props.placeholder}
              name={this.props.name}
            />
          </div>;
  },
  Textarea: function Textarea(props) {
    return <div className="col-xs-12">
            <textarea
              placeholder={this.props.placeholder}
              name={this.props.name}
            >
            </textarea>
          </div>;
  }
}

Then when your dot usage

<Field.Text placeholder="something" name="something" />
0
export default class Field extends React.Component {

  render() {
    switch (this.props.type) {
      case 'textarea': {
        return (
          <div className="col-xs-12">
            <textarea
              placeholder={this.props.placeholder}
              name={this.props.name}
            >
            </textarea>
          </div>
          )
      }
      case 'text': {
        return (
          <div className="col-md-6 col-lg-4">
            <input
              type="text"
              placeholder={this.props.placeholder}
              name={this.props.name}
            />
          </div>
        )
      }
    }
  }
}

chnage this as following way

const Field = {
    text: function(){
      // your text code
    }
}

export default Field;

Same way they have mentioned in the facebook react docs. Instead of component you can return object which contain your functions.

Andrew Li
  • 55,805
  • 14
  • 125
  • 143
suyesh
  • 659
  • 1
  • 10
  • 19