React-从父级到子级访问函数参数

时间:2018-09-21 11:50:32

标签: javascript reactjs

有点背景...

我正在用React创建一个应用程序(运行良好),但是对必须保留在父组件中的状态/功能数量感到沮丧。

我想做的是将某些状态和功能推送到子父组件,从而使其更易于管理。

我遇到问题的一个功能领域是Modal组件,该组件需要在父组件的JSX中呈现。

我已将此Modal设为可重用,因此它仅呈现{this.props.children}。内容由switch case语句决定,并根据其“模式”显示新的内容

问题...

不确定在React中是否为此使用一种模式,但是我想通过props将一个函数及其参数传递给另一个子组件,而该子组件将参数设置为其在渲染时的状态。

这是代码的简化版本,仅显示1个模式“模式/内容选项”:

import React, { Component } from "react";
import ReactDOM from "react-dom";

class Items extends Component {
    state = {
        categories: [
            {
                id: 1,
                name: "category 1",
                items: [
                    { name: "item 1", id: Math.floor(Math.random() * 99999) },
                    { name: "item 2", id: Math.floor(Math.random() * 99999) }
                ]
            },
            {
                id: 2,
                name: "category 2",
                items: [
                    { name: "item 3", id: Math.floor(Math.random() * 99999) },
                    { name: "item 4", id: Math.floor(Math.random() * 99999) }
                ]
            },
            {
                id: 3,
                name: "category 3",
                items: [
                    { name: "item 5", id: Math.floor(Math.random() * 99999) }
                ]
            }
        ],
        modalOpen: true,
        modalMode: ""
    };

    getClickedItem(item, category) {
        console.log("[click from parent component]", arguments);
        return arguments
    };

    openModal(mode, item, category) {
        if (mode === "editItem") {
            this.getClickedItem(item, category);
        }
        this.setState({
            modalOpen: true,
            modalMode: mode
        });
    }

    closeModal() {
        this.setState({
            modalOpen: false,
            modalMode: ""
        });
    }
    render() {
        const { categories, modalOpen, modalMode } = this.state;

        let modalContent;

        switch (modalMode) {
            case "editItem":
                modalContent = (
                    <Component1 closeModal={this.closeModal.bind(this)} getClickedItem={this.getClickedItem}/>
                );
                break;
            default:
                break;
        }

        return (
            <div>
                {categories.map(cat => {
                    return (
                        <ItemCategory
                            {...cat}
                            key={cat.id}
                            click={this.openModal.bind(this)}
                        />
                    );
                })}
                <Modal show={modalOpen}>{modalContent}</Modal>
            </div>
        );
    }
}

class ItemCategory extends Component {
    handleClick(item, category) {
        this.props.click("editItem", item, category);
    }
    render() {
        const { items, name } = this.props;

        const getItems = items.map(item => {
            return item;
        });

        return (
            <div>
                <div>-{name}</div>
                <ul>
                    {getItems.map(item => {
                        return (
                            <li
                                key={item.id}
                                onClick={() => this.handleClick(item, name)}
                            >
                                {item.name}
                            </li>
                        );
                    })}
                </ul>
            </div>
        );
    }
}

class Component1 extends Component {
    state = {
        item: "",
        category: ""
    }

    static getDerivedStateFromProps(props, state) {
        const getParams = props.getClickedItem()
        console.log("[from child component]", getParams)
    }

    render() {
        const { item, category } = this.state;
        const { closeModal } = this.props;

        return (
            <div>
                <h1>Component1 modal content</h1>
                <button onClick={closeModal}>Close</button>
                {item}
                {category}
            </div>
        );
    }
}

class Modal extends Component {
    render() {
        return (
            <div
                style={{
                    transform: this.props.show
                        ? "translateY(0)"
                        : "translateY(-100vh)",
                    opacity: this.props.show ? "1" : "0"
                }}
            >
                {this.props.children}
            </div>
        );
    }
}

function App() {
    return <Items />;
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

也可以作为代码笔https://codesandbox.io/s/m7jm5z0w4j

我认为该功能似乎可以传递给子组件。但是我无法使用父组件中的参数。

如果您需要更多详细信息,请告诉我。

谢谢:)

1 个答案:

答案 0 :(得分:1)

问题出在openModal和closeModal吗?

定义如下功能:

openModal = () => {
    this.setState({
        modalOpen: true
    });
}

然后将其作为道具传递

click={() => this.openModal()}

说明

我编写函数的方式实际上等同于编写这样的函数

constructor() {
    this.openModal = this.openModal.bind(this)
}

openModal() {
    this.setState({modalOpen: true}) 
} 

区别是我使用了粗箭头功能。

您可以像这样this.openModal()

调用该函数

然后,您必须将函数作为道具传递。如果将其作为this.openModal传递,则子组件将无法访问父状态,但是如果将其作为() => this.openModal()传递,则在传递函数之前先计算该函数的效果,这应该可以工作。这种传递函数的方式也适用于Angular。

更新

此功能

getClickedItem(item, category) {
    console.log("[click from parent component]", arguments);
    return arguments
};

参数未定义。

此外,您的openModal函数接受三个论点,但您都不通过。

实际上,您的代码看起来像是不能按原样工作。...但是,是的,将函数props作为胖箭头函数传递


工作-我已经大大更改了您的代码

import React, { Component } from "react";
import ReactDOM from "react-dom";

class Items extends Component {
  state = {
    categories: [
      {
        id: 1,
        name: "category 1",
        items: [
          { name: "item 1", id: Math.floor(Math.random() * 99999) },
          { name: "item 2", id: Math.floor(Math.random() * 99999) }
        ]
      },
      {
        id: 2,
        name: "category 2",
        items: [
          { name: "item 3", id: Math.floor(Math.random() * 99999) },
          { name: "item 4", id: Math.floor(Math.random() * 99999) }
        ]
      },
      {
        id: 3,
        name: "category 3",
        items: [{ name: "item 5", id: Math.floor(Math.random() * 99999) }]
      }
    ],
    modalOpen: false,
    selectedItem: {}
  };
  openModal = item => {
    this.setState({
      modalOpen: true,
      selectedItem: item
    });
  };

  closeModal = () => {
    this.setState({
      modalOpen: false
    });
  };
  render() {
    const { categories, modalOpen, selectedItem } = this.state;
    return (
      <div>
        {categories.map(cat => {
          return (
            <ItemCategory
              {...cat}
              key={cat.id}
              click={item => this.openModal(item)}
            />
          );
        })}
        <Modal show={modalOpen}>
          <Component1
            closeModal={() => this.closeModal()}
            item={selectedItem}
          />
        </Modal>
      </div>
    );
  }
}

class ItemCategory extends Component {
  handleClick = item => {
    this.props.click(item);
  };
  render() {
    const { items, name } = this.props;

    const getItems = items.map(item => {
      return item;
    });

    return (
  <div>
    <div>-{name}</div>
    <ul>
      {getItems.map(item => {
        return (
          <li key={item.id} onClick={() => this.handleClick(item)}>
            {item.name}
          </li>
        );
      })}
    </ul>
  </div>
);
  }
}

class Component1 extends Component {
  render() {
    const { item, closeModal } = this.props;
    console.log(item);
    return (
      <div>
        <h1>{item.name} modal content</h1>
        <button onClick={closeModal}>Close</button>
      </div>
    );
  }
}

class Modal extends Component {
  render() {
    return (
      <div
        style={{
          transform: this.props.show ? "translateY(0)" : "translateY(-100vh)",
          opacity: this.props.show ? "1" : "0"
        }}
      >
        {this.props.children}
      </div>
    );
  }
}

function App() {
  return <Items />;
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);