【问题标题】:Redux React Modal Local PropRedux React 模态本地属性
【发布时间】:2020-11-16 05:06:22
【问题描述】:

我是 React 和 Redux 的超级新手,但是如何同时使用本地属性和 redux 属性?我一直在尝试不同的方法,但它们似乎都不适用于我的情况,这很简单,我相信有一个简单的解决方案,在我没有经验的情况下我看不到。

我正在尝试做的事情:使用redux来管理角色状态,但同时使用本地组件来管理模态(打开和关闭它) 我想了解如何在此类代码中使用本地状态,或者如何更改它以使 isOpen 属性在本地级别可管理。

import * as React from "react";
import { Component, useState } from "react";

import { Character } from "../../../../Data/Character";
import StatusBar from "../../../Components/StatusBar";
import Button from "react-bootstrap/Button";
import Modal from "react-bootstrap/Modal";
import HealthCalculator from "./HealthCalculator";
import { connect } from "react-redux";
import { UpdateCurrentHealth } from "../../../../redux/actionCreators";

const mapStateToProps = (state: {
  currentHealth: any,
  maxHealth: any,
  classes: any[],
}) => {
  return {
    currentHealth: state.currentHealth,
    maxHealth: state.maxHealth,
    classes: state.classes,
    isOpen: false,
  };
};

const mapDispatchToProps = (dispatch) => ({
  updateCurrentHealth: (payload) => dispatch(UpdateCurrentHealth(payload)),
  toggleModal: () => ({}),
});

/....../

const HealthCard = (props: {
  currentHealth: number,
  maxHealth: number,
  classes: any[],
  isOpen: any,
}) => (
  <>
    <div className="card" style={{ textAlign: "center" }}>
      <span style={{ fontSize: "20px", color: "#708F93" }}>Hit Points</span>
      <div className="HealthBar">
        <StatusBar
          bColor="#9DBE9E"
          fColor="#BAE6BC"
          value={(props.currentHealth / props.maxHealth) * 100}
          label={GetLabelHealth(props.currentHealth, props.maxHealth)}
        />
      </div>
      {props.classes.length >= 0 &&
        props.classes.map((c) => (
          <div style={{ marginTop: "2px" }}>
            <div className="HitPointsBar">
              <StatusBar
                bColor="#c5d2db"
                fColor="#D8E2E9"
                value={(c.currentHDie / c.classLevel) * 100}
                label={GetLabelHitDice(c.currentHDie, c.hitDie)}
              />
            </div>
          </div>
        ))}
    </div>
    <Modal
      show={props.isOpen}
      size="sm"
      aria-labelledby="contained-modal-title-vcenter"
      centered
    >
      <Modal.Body bsPrefix="modalContentCard">
        <HealthCalculator />
      </Modal.Body>
    </Modal>
  </>
);

export default connect(mapStateToProps, mapDispatchToProps)(HealthCard);

【问题讨论】:

    标签: javascript reactjs redux


    【解决方案1】:

    如果您指的是处理模态状态的单张卡片,而不是通过props.isOpen 传递它,那么您可以进行点击事件或您需要模态打开的任何内容。我将更改您的示例,以便在您的 HealthCard 呈现时,模式将打开,只是为了向您展示挂钩的工作原理,并在单击时将其关闭:

    import * as React from "react";
    import { Component, useState } from "react";
    
    import { Character } from "../../../../Data/Character";
    import StatusBar from "../../../Components/StatusBar";
    import Button from "react-bootstrap/Button";
    import Modal from "react-bootstrap/Modal";
    import HealthCalculator from "./HealthCalculator";
    import { connect } from "react-redux";
    import { UpdateCurrentHealth } from "../../../../redux/actionCreators";
    import { useEffect } from "react";
    
    const mapStateToProps = (state: {
      currentHealth: any,
      maxHealth: any,
      classes: any[],
    }) => {
      return {
        currentHealth: state.currentHealth,
        maxHealth: state.maxHealth,
        classes: state.classes,
        isOpen: false,
      };
    };
    
    const mapDispatchToProps = (dispatch) => ({
      updateCurrentHealth: (payload) => dispatch(UpdateCurrentHealth(payload)),
      toggleModal: () => ({}),
    });
    
    const HealthCard = (props: {
      currentHealth: number,
      maxHealth: number,
      classes: any[],
      isOpen: any,
    }) => {
      const [isOpen, setIsOpen] = useState(false);
    
      useEffect(() => {
        setIsOpen(true);
      }, []);
    
      const onModalClose = () => {
        setIsOpen(false);
      };
    
      return (
        <>
          <div
            className="card"
            style={{ textAlign: "center" }}
            onClick={onModalClose}
          >
            <span style={{ fontSize: "20px", color: "#708F93" }}>Hit Points</span>
            <div className="HealthBar">
              <StatusBar
                bColor="#9DBE9E"
                fColor="#BAE6BC"
                value={(props.currentHealth / props.maxHealth) * 100}
                label={GetLabelHealth(props.currentHealth, props.maxHealth)}
              />
            </div>
            {props.classes.length >= 0 &&
              props.classes.map((c) => (
                <div style={{ marginTop: "2px" }}>
                  <div className="HitPointsBar">
                    <StatusBar
                      bColor="#c5d2db"
                      fColor="#D8E2E9"
                      value={(c.currentHDie / c.classLevel) * 100}
                      label={GetLabelHitDice(c.currentHDie, c.hitDie)}
                    />
                  </div>
                </div>
              ))}
          </div>
          <Modal
            show={isOpen}
            size="sm"
            aria-labelledby="contained-modal-title-vcenter"
            centered
          >
            <Modal.Body bsPrefix="modalContentCard">
              <HealthCalculator />
            </Modal.Body>
          </Modal>
        </>
      );
    };
    
    export default connect(mapStateToProps, mapDispatchToProps)(HealthCard);
    

    【讨论】:

    • 非常感谢!这回答了我的问题,我之前尝试过类似的东西,但不完全是这样。
    • 很高兴我的回答有帮助!
    【解决方案2】:

    维护local 状态(通过有状态类组件或useState 钩子完成)和redux 状态并没有什么神奇之处。因为在您的情况下,模态 isOpen 状态被认为是本地的,而其他道具则源自 redux:

    interface Props {
        // ownProps
        isOpen: Boolean,
        setIsOpen: Function,
        // mappedProps
        currentHealth: number,
        maxHealth: number,
        classes: Array<any>,
        setCurrentHealth: Function
    }
    
    const HealthCard = ({
        isOpen,
        setIsOpen,
        currentHealth,
        maxHealth,
        classes,
        setCurrentHealth
    }: Props) => {
        // component code
    };
    
    const mapStateToProps = (state: any) => ({
        currentHealth: state.currentHealth,
        maxHealth: state.maxHealth,
        classes: state.classes,
    });
    
    // you can get dispatch type from redux types
    const mapDispatchToProps = (dispatch: Dispatch) => ({
        updateCurrentHealth: (payload: any) => dispatch(UpdateCurrentHealth(payload)),
    });;
    
    export default connect(mapStateToProps, mapDispatchToProps)(HealthCard);
    

    然后您将调用组件并仅传递被视为ownProps 的道具:

    const Parent = () => {
        const [ isModalOpen, setIsModalOpen ] = useState(false);
        const toggleIsModalOpen = (event: SyntheticEvent): void => {
            setIsModalOpen(!isModalOpen);
        };
        
        // ...
        return (
            <>
                // ...
                <HealthCard isOpen={isModalOpen} toggleModal={toggleIsModalOpen}/>
            </>
        );
    };
    

    有关该主题的更多信息,我建议深入研究redux docsreact-redux docs 和另外的redux toolkit docs,这简直太棒了,它删除了大量无用的样板,同时还为您提供了有用的 redux 相关的基线设置实用程序(reselectredux-thunk 等)

    作为对未来有用的信息,mapStateToProps 还可以访问那些直接传递给组件的ownProps,该函数采用第二个可选参数:

    const mapStateToProps = (state, ownProps) => {
        // in your case, you could access the props "isOpen" and "toggleIsOpen" on this level
        // and manipulate redux state with them before injecting it into the component
    };
    

    希望这堵文字墙对您有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-11-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-16
      • 1970-01-01
      • 2020-06-21
      相关资源
      最近更新 更多