简体   繁体   English

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

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

I wanted to show logoff button after user signs in and hide visibility of button after the user logged out. 我想在用户登录后显示注销按钮,并在用户注销后隐藏按钮的可见性。 Menu items are coming from Menu.js file. 菜单项来自Menu.js文件。

The current workflow of the app is, if user signed in, the auth state is updated in the store, based on that state, I wanted to show a logoff Button in Menu. 该应用程序当前的工作流程是,如果用户登录,则将在商店中更新身份验证状态,基于该状态,我想在菜单中显示注销按钮。

The auth state is correctly updated in Redux store on login and I can get the value of auth in Menu.js File from Redux store, but the change is not rendered in Siderbar.js until i refresh the page. 登录后在Redux存储中正确更新了auth状态,我可以从Redux存储中获取Menu.js文件中auth的值,但是直到我刷新页面后,更改才在Siderbar.js中呈现。 What should i need to do in sidebar.js to fetch the menu on auth state change in Store. 我需要在sidebar.js中做什么才能在Store中获取身份验证状态更改菜单。

Siderbar.js 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));

What should i do in Sidebar.js, that it re-renders the menu on auth state change. 我应该在Sidebar.js中做什么,它会在身份验证状态更改时重新呈现菜单。

Any help would be highly appreciated. 任何帮助将不胜感激。

Menu.js File 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)

Inside the parent component of your log out button you can conditionally render the log out button; 在注销按钮的上级组件内部,您可以有条件地呈现注销按钮。 take note this means your parent component is connected to redux via connect(mapStateToProps) 请注意,这意味着您的父组件通过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