Можно ли получить имя вложенного внутреннего React-компонента, вызвав функцию из одного из ее компонентов? - PullRequest
0 голосов
/ 07 февраля 2019

У меня есть этот компонент:

class DashboardPage extends Component {
  constructor(props) {
    super(props);

    this.state = {
      loading: true,
      shownPage: ActiveDeals,
      error: false,
      errorDetails: null,
      activeIcon: "Home"
    };
  }

  componentDidMount() {
    //
  }

  setShownPage = (name, iconName) => () => {
    this.setState({ shownPage: name, activeIcon: iconName });
  };

  getIconColor = () => {
    // could I call this from the Home component and check its name? Or know the caller?
    return "primary";
  };

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

    const menuItems = (
      <List>
        <ListItem className={classNames(classes.listItem)} button onClick={this.setShownPage(ActiveDeals, "Home")}>
          <ListItemIcon className={classNames(classes.listItemIcon)}>
            <Home color={this.state.activeIcon === "Home" ? "primary" : "secondary"} />
          </ListItemIcon>
        </ListItem>
        <ListItem className={classNames(classes.listItem)} button onClick={this.setShownPage(UpcomingDates, "CalendarToday")}>
          <ListItemIcon className={classNames(classes.listItemIcon)}>
            <CalendarToday color={this.state.activeIcon === "CalendarToday" ? "primary" : "secondary"} />
          </ListItemIcon>
        </ListItem>
        <ListItem className={classNames(classes.listItem)} button onClick={this.setShownPage(DealsPipeline, "FilterList")}>
          <ListItemIcon className={classNames(classes.listItemIcon)}>
            <FilterList color={this.state.activeIcon === "FilterList" ? "primary" : "secondary"} />
          </ListItemIcon>
        </ListItem>
      </List>
    );

    return (
      <MainFrame
        route={this.props.match.url}
        title={this.state.shownPage.title}
        menuItems={menuItems}
        open={this.state.open}
        topRightFeature={this.state.shownPage.topRightFeature}
      >
        <this.state.shownPage />
        <div>Primary color is {this.props.theme.palette.primary.main}</div>
      </MainFrame>
    );
  }
}

export default withStyles(styles, { withTheme: true })(DashboardPage);

... Я привык использовать nameof() и type() в языках бэкэнда, чтобы знать имя данного экземпляра.В React мне еще предстоит найти способ сделать это.

Вместо того, чтобы устанавливать цвета значков в зависимости от состояния (которое использует жестко закодированные строки, чёрт возьми), я хочу использовать функциональный способ обхода дерева dom донайти относительных потомков или способ просто узнать имя значка, вызывающего метод getIconColor, чтобы я мог сравнить его с активным состоянием.

Есть ли способ для компонента установитьсвойство при использовании функции, которая «знает», что она была вызвана, например, Home?

Ответы [ 2 ]

0 голосов
/ 07 февраля 2019

Я думаю, что вы пытаетесь решить эту проблему таким образом, чтобы не упустить декларативную силу React и возможности, которые предоставляет композиция компонентов.Дублирование кода между элементами списка требует введения другого компонента:

const listItemStyles = {
  listItem: {
    /* whatever styles you need */
  },
  listItemIcon: {
    /* whatever styles you need */
  }
};
const DashboardListItem = withStyles(listItemStyles)(
  ({ Page, Icon, ShownPage, classes, setShownPage }) => {
    return (
      <ListItem
        className={classes.listItem}
        button
        onClick={() => setShownPage(Page)}
      >
        <ListItemIcon className={classes.listItemIcon}>
          <Icon color={ShownPage === Page ? "primary" : "secondary"} />
        </ListItemIcon>
      </ListItem>
    );
  }
);

Тогда ваш menuItems становится:

const menuItems = [
  { Page: ActiveDeals, Icon: Home },
  { Page: UpcomingDates, Icon: CalendarToday },
  { Page: DealsPipeline, Icon: FilterList }
];
const mappedMenuItems = menuItems.map((menuItem, index) => (
  <DashboardListItem
    key={index}
    {...menuItem}
    ShownPage={this.state.shownPage}
    setShownPage={this.setShownPage}
  />
));

Полный код выглядит следующим образом:

import React, { Component } from "react";
import List from "@material-ui/core/List";
import ListItem from "@material-ui/core/ListItem";
import ListItemIcon from "@material-ui/core/ListItemIcon";
import { withStyles } from "@material-ui/core/styles";
import Home from "@material-ui/icons/Home";
import CalendarToday from "@material-ui/icons/CalendarToday";
import FilterList from "@material-ui/icons/FilterList";
const styles = {};
const ActiveDeals = () => {
  return <div>ActiveDeals Page!</div>;
};
const UpcomingDates = () => {
  return <div>UpcomingDates Page!</div>;
};
const DealsPipeline = () => {
  return <div>DealsPipeline Page!</div>;
};
const listItemStyles = {
  listItem: {
    /* whatever styles you need */
  },
  listItemIcon: {
    /* whatever styles you need */
  }
};
const DashboardListItem = withStyles(listItemStyles)(
  ({ Page, Icon, ShownPage, classes, setShownPage }) => {
    return (
      <ListItem
        className={classes.listItem}
        button
        onClick={() => setShownPage(Page)}
      >
        <ListItemIcon className={classes.listItemIcon}>
          <Icon color={ShownPage === Page ? "primary" : "secondary"} />
        </ListItemIcon>
      </ListItem>
    );
  }
);
const menuItems = [
  { Page: ActiveDeals, Icon: Home },
  { Page: UpcomingDates, Icon: CalendarToday },
  { Page: DealsPipeline, Icon: FilterList }
];

class DashboardPage extends Component {
  constructor(props) {
    super(props);

    this.state = {
      shownPage: ActiveDeals
    };
  }

  setShownPage = page => {
    this.setState({ shownPage: page });
  };

  render() {
    const mappedMenuItems = menuItems.map((menuItem, index) => (
      <DashboardListItem
        key={index}
        {...menuItem}
        ShownPage={this.state.shownPage}
        setShownPage={this.setShownPage}
      />
    ));
    return (
      <div>
        <List>{mappedMenuItems}</List>

        <this.state.shownPage />
        <div>Primary color is {this.props.theme.palette.primary.main}</div>
      </div>
    );
  }
}

export default withStyles(styles, { withTheme: true })(DashboardPage);

Вот рабочий пример:

Edit DashboardPage

0 голосов
/ 07 февраля 2019

Вы можете получить идентификацию вызывающего абонента, если связываете функцию в компоненте, где она используется.Это будет работать только в компоненте класса.

Примерно так:

class Apple extends React.Component {
  constructor(props) {
    super(props);
    this.getName = props.getName.bind(this);
  }
  render() {
    return <div>I am an {this.getName()}</div>;
  }
}

class Banana extends React.Component {
  getName() {
    return this.constructor.name;
  }
  render() {
    return (
      <div className="App">
        <Apple getName={this.getName} />
      </div>
    );
  }
}

https://codesandbox.io/s/247lpxl4j0

...