【问题标题】:Should I be using React State for user-interactions (to toggle visibility classes)?我应该使用 React State 进行用户交互(切换可见性类)吗?
【发布时间】:2018-11-13 10:48:17
【问题描述】:

我正在开发一个 UI 库,我的一些组件会根据用户的一些交互来改变它们的“状态”。

例如,用户单击手风琴面板的标题会导致手风琴面板打开并变得可见。这种状态是通过将visible 修饰符添加到手风琴面板来实现的,如下所示。:

<div class="accordion">
    <div class="accordion_panel-visible">
        <div class="accordion_title">foo</div>
        <div class="accordion_content">bar</div>
    </div>
    <div class="accordion_panel">
        <div class="accordion_title">fizz</div>
        <div class="accordion_content">buzz</div>
    </div>
</div>

我之前的假设是 React State 应该用于根据一些后端数据重新渲染组件。但是,基于查看其他 UI 库等的源代码,它们似乎也在使用 React State 处理 UI 状态。

所以使用 React,我可以通过使用原始 DOM API 来实现我想要的(如这里的示例所示 - https://reactjs.org/docs/refs-and-the-dom.html):

Accordion.defaultProps = {
    name: 'accordion'
};

class Accordion extends React.Component {
    toggle(event) {
        const panel = event.target.closest('[data-component="panel"]');
        const operator = panel.modifier('active') ? 'unset' : 'set';

        panel.modifier('active', operator); 
    }

    render() {
        return (
            <Module {...this.props}>
                {this.props.panels.map(({ title, content }, index) => (
                    <Component name='panel' key={index}>
                        <Component name='title' onClick={this.toggle}>{title}</Component>
                        <Component name='content'>{content}</Component>
                    </Component>
                ))}
            </Module>
        )
    }
}

这一切都很好——但我本质上是从一个 React 组件中进行 DOM 操作,我经常阅读应该避免。在这种情况下,我应该使用 React State 和 Refs(而不是直接的 DOM 操作)。为了实现与上述相同的目标,我相信我可以做到:

Accordion.defaultProps = {
    name: 'accordion'
};

class Accordion extends React.Component {
    constructor(props) {
        super(props);

        this.panels = [];
        this.state = { activePanel: null };
    }

    toggle(index) {
        this.setState({ 
            activePanel: (this.panels[index] === this.state.activePanel) ? null : this.panels[index]
        });
    }

    isActive(index) {
        return (this.panels[index] === this.state.activePanel) ? true : false;
    }

    render() {
        return (
            <Module {...this.props}>
                {this.props.panels.map(({ title, content }, index) => (
                    <Component name='panel' 
                        key={index} 
                        ref={ref => this.panels[index] = ref}
                        modifiers={this.isActive(index) ? 'active' : false}
                    >
                        <Component name='title' onClick={this.toggle.bind(this, index)}>
                            {title}
                        </Component>
                        <Component name='content'>{content}</Component>
                    </Component>
                ))}
            </Module>
        )
    }
}

(我知道上面的 sn-p 的行为会关闭同级面板,这不是第一个 sn-p 的情况,但这是微不足道的,可以忽略)。

所以我的问题是,我是否应该为此使用 React State(即后一个示例)?

感觉就像我的应用正在显示/隐藏/打开/关闭基于 用户交互 的 UI 元素,这些元素不需要/修改/发布/更新/获取/接收任何方式的数据,那么 React 不应该真正关心它们。

但最重要的是 - 这取决于偏好 吗?是否应该由 me 来决定 React 是否应该关心这个?归根结底,React 是一个工具,我目前正在使用该工具在后端免费环境中创建和渲染 UI 组件。我现在真的很困惑,不确定我是否真的能看到在这种情况下使用 state 的好处。

谢谢!

【问题讨论】:

  • 通常直接 dom 操作不是一个好主意,如果它是一个反应组件正在使用的东西,除非该项目与组件没有相关性(这意味着如果你只是想从你可以抓住的东西中获取价值它通过 DOM 而不是使用 ref.. 等)。也就是说,通常当组件需要切换不与任何其他组件共享的视图时,您会使用状态。如果它是多个组件所需的变量,则应将其移至某个商店。
  • 另外,如果某些操作是繁重的操作(例如 requestAnimationFrame,您正在为某物制作动画或渲染画布,您在鼠标移动时绘制某物......这不需要状态,您将不需要组件生命周期,只需画布或直接 dom 操作)。所以我想这个故事的寓意是状态是一个非常有用的工具,但具体取决于用例。如果它是一个繁重的操作,你可能可以避免状态,如果它是多个组件需要的东西,那么可能又想使用一个商店。 state 有利于本地操作
  • 感谢@JohnRuddell - 有用且有见地。听起来我应该在我的上下文中使用状态。但是,问题仍然在于为什么,除了为了它,因为“这是正确的 React 方式”——在我分享的示例中,React State 方式需要更多代码并且可读性较差,至少对我来说。但我想确保我了解全部情况,包括我尚未考虑的事情。
  • 好吧,如果你不使用 state 并直接改变 dom,那么使用 react 有什么意义。 React 不再知道任何元素中的内容,这使得它变得毫无意义。您可以利用 JS 内存中元素的强大功能。老实说,虽然我通常避免使用 state,但我的存储使用 redux,如果可能的话,尽量使用功能组件。我用于切换侧边栏的状态等等
  • 这里有一些链接供您阅读。 medium.freecodecamp.org/… ... camjackson.net/post/9-things-every-reactjs-beginner-should-know ... engineering.opsgenie.com/… 第一个链接谈到了在 JS 中利用 html 的力量以及你可以用它做什么

标签: reactjs user-interface ref react-state-management


【解决方案1】:

据我了解,您只想将后端/通信和业务逻辑置于“React 状态”。但正如您自己指出的那样,还有与 UI 元素相关的状态。手风琴关闭/打开等。

可以将其分为两类:

   - UI State (only for representation purposes)
   - Business Logic state

你可以同时使用 React 的组件状态。

在构建或使用 UI 组件库时,为了封装,状态通常在这些库中保存/管理。对于复杂的应用程序,我建议使用一些更强大的状态管理,例如react-redux。但也有一些情况是人们将 react-redux 用于 UI 业务逻辑状态。

从可重用性的角度来看,我建议使用不了解实际应用用例的 UI 组件(如 Accordion、FancyButton、Snackbar 等)。以及组成整个页面或部分页面的另一个组件集合(页眉、页脚、导航、MainView 等)。

然后 - 在使用 redux 时 - 你可以拥有所谓的容器,它将组件与 redux 的存储/状态管理连接起来。

在任何情况下,都应该避免使用 refs 进行“简单”的状态修改。通常只有在包含 3rd 方库(类似 jQuery)或 WebComponents/Custom Elements 时才需要这样做,因为它们可能无法很好地与 React 道具等配合使用。

关于来自 cmets 的问题:具有呈现常见问题 (FAQ) 的任务,该组件可能如下所示:

应用相关的 UI 组件(“傻瓜”),./components/FAQ.js:

const FAQ = ({faqs}) => (
  <Accordion>
    {faqs.map(faq => (
      <AccordionPane title={faq.title} content={faq.text} />
    ))}
  </Accordion>
)

并且 - 使用 redux - 各自的 Container,./containers/FAQ.js:

import {connect} from 'react-redux'
import FAQ from './FAQ'

const mapStateToProps = state => state.faqs

export default connect(mapStateToProps)(FAQ)

【讨论】:

  • 您对我的担忧的理解是正确的。 “你可以同时使用 React 的组件状态。” - 虽然我当然可以,但我正在尝试确定我是否应该。拥有不知道实际应用程序的 UI 组件正是我的目标 - 虽然我使用 React 呈现原始组件,但我仍然觉得state 应该在原始组件被应用时发挥作用 在有意义的上下文中。所以就我的应用而言,state 可能是“了解更多手风琴已打开”,但就我的 UI 而言,它为什么还需要知道“第二个面板已打开”?
  • 我明白了。 Accordion UI 组件实际上应该有一个AccordionContainer,它负责状态处理(最多只能打开 1 个手风琴)。所以 UI Component 实际上是两个:&lt;AccordionContainer&gt;&lt;Accordion ... /&gt;&lt;Accordion .../&gt;&lt;/AccordionCollection&gt;。或者正如您将它们命名为 "Accordion" => "AccordionCollection" 和 "AccordionPanel" => "Accordion"。
  • 在理想的世界中,AccordionContainer 不应该根据您的应用程序及其使用的上下文命名为更具语义性的名称吗?所以也许&lt;FrequentlyAskedQuestions&gt;&lt;Accordion ... /&gt;&lt;Accordion .../&gt;&lt;/FrequentlyAskedQuestions&gt;?抱歉,如果我只是在这里增加混乱。
  • 使用我正在构建的 API,我希望做类似 const FAQ = ({faqs}) =&gt; (&lt;Accordion panels={faqs} /&gt;) 的事情 - 就应用程序而言,这是一个常见问题解答而不是手风琴,手风琴就是它的呈现方式(所以理论上我可以做到const FAQ = ({faqs}) =&gt; (&lt;Tabs tabs={faqs} /&gt;)),因此任何与它的呈现方式有关的逻辑都不应该暴露给应用程序,这就是为什么我质疑我在我的组件。最终,我正在构建一个供开发人员使用的库,我如何做到这一点会对他们和他们的应用产生影响
  • 如果我选择处理这些交互,我正在尝试考虑我的图书馆的最终用户在构建他们的应用程序(如果有的话)时可能需要做哪些不同的事情using state(这个库开始是一个通用的 CSS + JS UI 库,我开始使用 React 来渲染标记,现在基本上我在这里)。
猜你喜欢
  • 2020-05-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-15
  • 1970-01-01
  • 1970-01-01
  • 2014-03-02
相关资源
最近更新 更多