React - 呈现动态内容的正确方法?

问题描述 投票:0回答:1

我想通过向其注入一个组件来使模态视图具有动态内容。

class RootView extends Component {
    state = {
        modalBody: null
    }

    setModalBody = (body) => {
        this.setState({modalBody: body})
    }

    render() {
        return(<ContextProvider value={this.setModalBody}><Modal>{this.state.modalBody}</Modal></ContextProvider>)
    }
}

然后在任何儿童视图内我使用setState来改变父亲modalBody

modalBody可以在每条路线上设置,这意味着modalBody可以是input列表,selection列表或仅文本。因此,modalBody必须具有控制这些输入的状态。

通过这种方式,它呈现正常,但状态更改后无法更新动态内容。父母的动态内容无法接收ChildView新状态,我必须在重新渲染后一次又一次地使用setModalBody

例如,如果modalBody中的输入已更改,则无法更新父级。

class ChildView extends Component {
    state = {
        inputValue: null
    }

    handleChange = (e) => {
        this.setState({inputValue: e.target.value})
    }


    setModalBody(body) {
        this.props.context.setModalBody(<input value={this.state.inputValue} onChange={this.handleChange} />)
    }

    render() {
        return(<Modal>{this.state.modalBody}</Modal>)
    }
}

完整代码:https://codesandbox.io/s/lp5p20mx1m将动态内容呈现给父级的任何正确方法?

reactjs state dynamic-content
1个回答
1
投票

我不知道为什么你需要创建一个父Modal组件,当你可以使Modal成为一个简单的可重复使用的child组件。

有关如何实现控制子模态的有状态父级的详细说明,请参阅here


但是,如果你必须有一个父Modal组件,那么你可以创建一个render prop传递props以供其children使用。

工作范例:

Edit Parent Modal

components / Modal.js(parent组件 - 这有很多较小的组件,为了可重用性和易于理解而分开 - 它们基本上是简单的divs,附带一些styles - 请参阅下面的注释)

import React, { Fragment, Component } from "react";
import PropTypes from "prop-types";
import BackgroundOverlay from "../BackgroundOverlay"; // grey background
import ClickHandler from "../ClickHandler"; // handles clicks outside of the modal
import Container from "../Container"; // contains the modal and background
import Content from "../Content"; // renders the "children" placed inside of <Modal>...</Modal>
import ModalContainer from "../ModalContainer"; // places the modal in the center of the page


class Modal extends Component {
  state = { isOpen: false };

  handleOpenModal = () => {
    this.setState({ isOpen: true });
  };

  handleCloseModal = () => {
    this.setState({ isOpen: false });
  };


  // this is a ternary operator (shorthand for "if/else" -- if cond ? then : else)
  // below can be read like: if isOpen is true, then render the modal,
  // else render whatever the child component is returning (in this case,
  // initially returning an "Open Modal" button)
  render = () =>
    this.state.isOpen ? (
      <Container>
        <BackgroundOverlay />
        <ModalContainer>
          <ClickHandler
            isOpen={this.state.isOpen}
            closeModal={this.handleCloseModal}
          >
            <Content>
              {this.props.children({
                isOpen: this.state.isOpen,
                onCloseModal: this.handleCloseModal,
                onOpenModal: this.handleOpenModal
              })}
            </Content>
          </ClickHandler>
        </ModalContainer>
      </Container>
    ) : (
      <Fragment>
        {this.props.children({
          isOpen: this.state.isOpen,
          onCloseModal: this.handleCloseModal,
          onOpenModal: this.handleOpenModal
        })}
      </Fragment>
    );
}

// these proptype declarations are to ensure that passed down props are 
// consistent and are defined as expected
Modal.propTypes = {
  children: PropTypes.func.isRequired // children must be a function
};

export default Modal;

components / Example.js(child组件接受来自isOpenonCloseModalonOpenModalparent - 正如你所注意到的,有重复的isOpen逻辑。虽然这种方法让你完全控制父,但它是重复的。但是,你可以通过将“Open Modal”按钮逻辑移动到父级来简化你的组件,并传递像<Modal btnTitle="Open Modal">这样的道具使其有些灵活,但是当isOpenfalse时你仍然会失去对最初渲染的内容的控制。)

import React, { Fragment } from "react";
import Modal from "../Modal";
import "./styles.css";

const Example = () => (
  <div className="example">
    <h2>Parent Modal Example</h2>
    <Modal>
      {({ isOpen, onCloseModal, onOpenModal }) =>
        isOpen ? (
          <Fragment>
            <h1 className="title">Hello!</h1>
            <p className="subtitle">There are two ways to close this modal</p>
            <ul>
              <li>Click outside of this modal in the grey overlay area.</li>
              <li>Click the close button below.</li>
            </ul>
            <button
              className="uk-button uk-button-danger uk-button-small"
              onClick={onCloseModal}
            >
              Close
            </button>
          </Fragment>
        ) : (
          <button
            className="uk-button uk-button-primary uk-button-small"
            onClick={onOpenModal}
          >
            Open Modal
          </button>
        )
      }
    </Modal>
  </div>
);

export default Example;
© www.soinside.com 2019 - 2024. All rights reserved.