繁体   English   中英

在Redux Store中的状态更改中重新渲染组件

[英]Re-Render in component on State Change in Redux Store

我想在用户登录后显示注销按钮,并在用户注销后隐藏按钮的可见性。 菜单项来自Menu.js文件。

该应用程序当前的工作流程是,如果用户登录,则将在商店中更新身份验证状态,基于该状态,我想在菜单中显示注销按钮。

登录后在Redux存储中正确更新了auth状态,我可以从Redux存储中获取Menu.js文件中auth的值,但是直到我刷新页面后,更改才在Siderbar.js中呈现。 我需要在sidebar.js中做什么才能在Store中获取身份验证状态更改菜单。

Siderbar.js

<pre><code>
import React, { Component } from 'react';
import { withNamespaces, Trans } from 'react-i18next';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { Link, withRouter } from 'react-router-dom';
import { Collapse, Badge } from 'reactstrap';
import SidebarRun from './Sidebar.run';
import SidebarUserBlock from './SidebarUserBlock';

import Menu from '../../Menu';

/** Component to display headings on sidebar */
const SidebarItemHeader = ({item}) => (
    <li className="nav-heading">
        <span><Trans i18nKey={item.translate}>{item.heading}</Trans></span>
    </li>
)

/** Normal items for the sidebar */
const SidebarItem = ({item, isActive}) => (
    <li className={ isActive ? 'active' : '' }>
        <Link to={item.path} title={item.name}>
            {item.label && <Badge tag="div" className="float-right" color={item.label.color}>{item.label.value}</Badge>}
            {item.icon && <em className={item.icon}></em>}
            <span><Trans i18nKey={item.translate}>{item.name}</Trans></span>
        </Link>
    </li>
)

/** Build a sub menu with items inside and attach collapse behavior */
const SidebarSubItem = ({item, isActive, handler, children, isOpen}) => (
    <li className={ isActive ? 'active' : '' }>
        <div className="nav-item" onClick={ handler }>
            {item.label && <Badge tag="div" className="float-right" color={item.label.color}>{item.label.value}</Badge>}
            {item.icon && <em className={item.icon}></em>}
            <span><Trans i18nKey={item.translate}>{item.name}</Trans></span>
        </div>
        <Collapse isOpen={ isOpen }>
            <ul id={item.path} className="sidebar-nav sidebar-subnav">
                { children }
            </ul>
        </Collapse>
    </li>
)

/** Component used to display a header on menu when using collapsed/hover mode */
const SidebarSubHeader = ({item}) => (
    <li className="sidebar-subnav-header">{item.name}</li>
)

class Sidebar extends Component {

    state = {
        collapse: {},
        isLoggedIn: ''
    }

    componentDidMount() {
        // pass navigator to access router api
        SidebarRun(this.navigator.bind(this));
        // prepare the flags to handle menu collapsed states
        this.buildCollapseList()
    }

    /** prepare initial state of collapse menus. Doesnt allow same route names */
    buildCollapseList = () => {
        let collapse = {};

        Menu
            .filter(({heading}) => !heading)
            .forEach(({name, path, submenu}) => {
                collapse[name] = this.routeActive(submenu ? submenu.map(({path})=>path) : path)
            })
        this.setState({collapse});
    }

    navigator(route) {
        this.props.history.push(route);
    }

    routeActive(paths) {
        paths = Array.isArray(paths) ? paths : [paths];
        return paths.some(p => this.props.location.pathname.indexOf(p) > -1)
    }

    toggleItemCollapse(stateName) {
        for (let c in this.state.collapse) {
            if (this.state.collapse[c] === true && c !== stateName)
                this.setState({
                    collapse: {
                        [c]: false
                    }
                });
        }
        this.setState({
            collapse: {
                [stateName]: !this.state.collapse[stateName]
            }
        });
    }

    getSubRoutes = item => item.submenu.map(({path}) => path)

    /** map menu config to string to determine what element to render */
    itemType = item => {
        if (item){
        // console.log(item)
            if (item.heading) return 'heading';
            if (!item.submenu) return 'menu';
            if (item.submenu) return 'submenu';
    }}

    render() {
        return (
            <aside className='aside-container'>
                { /* START Sidebar (left) */ }
                <div className="aside-inner">
                    <nav data-sidebar-anyclick-close="" className="sidebar">
                        { /* START sidebar nav */ }
                        <ul className="sidebar-nav">
                            { /* START user info */ }
                            <li className="has-user-block">
                                <SidebarUserBlock/>
                            </li>
                            { /* END user info */ }

                            { /* Iterates over all sidebar items */ }
                            {
                                Menu.map((item, i) => {
                                    // heading
                                    if(this.itemType(item) === 'heading')
                                        return (
                                            <SidebarItemHeader item={item} key={i} />
                                        )
                                    else {
                                        if(this.itemType(item) === 'menu')
                                            return (
                                                <SidebarItem isActive={this.routeActive(item.path)} item={item} key={i} />
                                            )
                                        if(this.itemType(item) === 'submenu')
                                            return [
                                                <SidebarSubItem item={item} isOpen={this.state.collapse[item.name]} handler={ this.toggleItemCollapse.bind(this, item.name) } isActive={this.routeActive(this.getSubRoutes(item))} key={i}>
                                                    <SidebarSubHeader item={item} key={i}/>
                                                    {
                                                        item.submenu.map((subitem, i) =>
                                                            <SidebarItem key={i} item={subitem} isActive={this.routeActive(subitem.path)} />
                                                        )
                                                    }
                                                </SidebarSubItem>
                                            ]
                                    }
                                    return null; // unrecognized item
                                })
                            }
                        </ul>
                        { /* END sidebar nav */ }
                    </nav>
                </div>
                { /* END Sidebar (left) */ }
            </aside>
        );
    }
}

Sidebar.propTypes = {
    isLoggedIn: PropTypes.object.isRequired
};
const mapStateToProps = (state, ownProps) => {
    // console.log("Sidebar: ", state.auth);
    return{
        isLoggedIn: state.auth,
}}

export default connect(mapStateToProps)(withRouter(Sidebar));

我应该在Sidebar.js中做什么,它会在身份验证状态更改时重新呈现菜单。

任何帮助将不胜感激。

Menu.js文件



    import configureStore from './store/store';
    const store = configureStore();

    function select(state) {
        return state.auth
    }

        let loggedIn = select(store.getState());

        let Meu = [

        {
            name: 'Analytics',
            icon: 'icon-speedometer',
            translate: 'sidebar.nav.DASHBOARD',
            submenu: [{
                    name: 'Overview',
                    path: '/dashboard',
                    translate: 'sidebar.nav.element.HOME'
                },
                {
                    name: 'Revenue',
                    path: '/revenue',
                    translate: 'sidebar.nav.element.REVENUE'
                },
                {
                    name: 'Source',
                    path: '/source',
                    translate: 'sidebar.nav.element.SOURCE'
                },
                {
                    name: 'Marketing',
                    path: '/marketing',
                    translate: 'sidebar.nav.element.MARKETING'
                }
            ]
        },
        {
            name: 'Tools',
            icon: 'fa fa-briefcase',
            translate: 'sidebar.nav.TOOLS',
            submenu: [
                {
                    name: 'Customer Service',
                    path: '/customer-service',
                    translate: 'sidebar.nav.element.CUSTOMER-SERVICE'
                }

            ]
        },

        {
            name: 'Settings',
            icon: 'icon-settings',
            translate: 'sidebar.nav.SETTINGS',
            submenu: [{
                    name: 'Profile Settings',
                    path: '/profile',
                    translate: 'sidebar.nav.element.PROFILE-SETTINGS'
                },
                {
                    name: 'Company Settings',
                    path: '/company-settings',
                    translate: 'sidebar.nav.element.SETTINGS'
                }
            ]
        },

        {(loggedIn.authResponse) ?
            ({
                name: 'Logoff',
                icon: 'icon-lock',
                path: '/logoff' 
            }) : null
        }
    ];
        const Menu = Meu.filter(word => word !== null) 
        export default (Menu)

在注销按钮的上级组件内部,您可以有条件地呈现注销按钮。 请注意,这意味着您的父组件通过connect(mapStateToProps)连接到redux

{ this.props.isLoggedIn ? <Button>Log Out</Button> : null }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM