How do I utilize dot notation when rendering components?
Asked Answered
S

4

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?

Swelter answered 5/7, 2017 at 4:7 Comment(0)
D
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.

Dressing answered 5/7, 2017 at 4:14 Comment(3)
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 <Control.select> or <Control.textarea>. are they also doing so with just exporting under name of Control?Swelter
@Swelter 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.Dressing
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.Swelter
D
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" />
Damsel answered 5/7, 2017 at 4:24 Comment(0)
P
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.

Paxon answered 5/7, 2017 at 4:20 Comment(0)
A
0

my working typescript codes to lazy import dot notation module. for example Nav, Nav.Item, Nav.Menu` from library react suite

Original import without react lazy from react suite docs

import { Nav, Navbar } from 'rsuite';

<Nav>
  <Nav.Item icon={<HomeIcon />} href="/page">
    Home
  </Nav.Item>
  <Nav.Item href="/page/google/login">Login</Nav.Item>
  <Nav.Menu title="Tools">
    <Nav.Item onClick={navItemClick} href="/page/bot-detect">
      Selenium Checker
    </Nav.Item>
    <Nav.Item onClick={navItemClick} href="/page/moment-timezone">
      Moment Timezone Playground
    </Nav.Item>
    <Nav.Item onClick={navItemClick} href="/page/cookies">
      Cookie Manager
    </Nav.Item>
  </Nav.Menu>
</Nav>

Convert using React Lazy import

const Nav = React.lazy(() => import('rsuite/esm/Nav'));
const NavItem = React.lazy(
  () => import('rsuite/esm/Nav').then(module => ({
    default: module.default.Item,
  })),
);
const NavMenu = React.lazy(
  () => import('rsuite/esm/Nav').then(module => ({
    default: module.default.Menu,
  })),
);

usage

<Nav>
  <NavItem icon={<HomeIcon />} href="/page">
    Home
  </NavItem>
  <NavItem href="/page/google/login">Login</NavItem>
  <NavMenu title="Tools">
    <NavItem onClick={navItemClick} href="/page/bot-detect">
      Selenium Checker
    </NavItem>
    <NavItem onClick={navItemClick} href="/page/moment-timezone">
      Moment Timezone Playground
    </NavItem>
    <NavItem onClick={navItemClick} href="/page/cookies">
      Cookie Manager
    </NavItem>
  </NavMenu>
</Nav>

result

I also write full code on my blog

Acrobatics answered 18/9, 2023 at 5:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.