我是否应该使用React State进行用户交互(切换可见性类)?

时间:2018-06-04 06:53:01

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

我正在开发一个UI库,我的一些组件改变了他们的状态"基于用户的一些互动。

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

<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>
        )
    }
}

(我知道上面代码段的行为会关闭兄弟面板,但第一个代码段的情况并非如此,但这是微不足道的,可以忽略不计。)

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

感觉就像我的应用程序显示/隐藏/打开/关闭基于用户交互的UI元素,这些元素不需要/修改/发布/更新/获取/接收数据,那么React实际上并不应该关心它们。

但最重要的是 - 归结为偏好?应该是谁决定React是否应该关心这个?在一天结束时,react是一个工具,我目前用于在后端自由环境中创建和呈现UI组件的工具。我现在真的很困惑,不确定在这种情况下我是否能真正看到使用state的好处。

谢谢!

1 个答案:

答案 0 :(得分:1)

据我了解您的疑虑,您只想将后端/通信和业务逻辑放入&#34; React状态&#34;。但正如你自己指出的那样,还有与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为&#34;简单&#34;应避免国家修改。通常这只是必需的,如果你包括第三方库(jQuery之类)或WebComponents/Custom Elements,因为他们可能不会很好地使用React道具等开箱即用。

关于评论中的问题:执行渲染FrequentlyAskedQuestions(FAQs)的任务,组件可能如下所示:

与应用程序相关的UI组件(&#34;愚蠢&#34;),。/ component /FAQ.js:

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

并且 - 使用redux - 相应的容器,./containers /FAQ.js:

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

const mapStateToProps = state => state.faqs

export default connect(mapStateToProps)(FAQ)