3

I have an application with a table, the table has a checkbox to set a Tenant as Active, this variable is a global variable that affects what the user does in other screens of the application.

On the top right of the application, I have another component called ActiveTenant, which basically shows in which tenant the user is working at the moment.

enter image description here

The code of the table component is like this:

import React, { Component } from 'react';
import {  Table, Radio} from 'antd';
import { adalApiFetch } from '../../adalConfig';
import Notification from '../../components/notification';

class ListTenants extends Component {

    constructor(props) {
        super(props);
        this.state = {
            data: []
        };
    }



    fetchData = () => {
        adalApiFetch(fetch, "/Tenant", {})
          .then(response => response.json())
          .then(responseJson => {
            if (!this.isCancelled) {
                const results= responseJson.map(row => ({
                    key: row.id,
                    TestSiteCollectionUrl: row.TestSiteCollectionUrl,
                    TenantName: row.TenantName,
                    Email: row.Email
                  }))
              this.setState({ data: results });
            }
          })
          .catch(error => {
            console.error(error);
          });
      };


    componentDidMount(){
        this.fetchData();
    }

    render() {
        const columns = [
                {
                    title: 'TenantName',
                    dataIndex: 'TenantName',
                    key: 'TenantName',
                }, 
                {
                    title: 'TestSiteCollectionUrl',
                    dataIndex: 'TestSiteCollectionUrl',
                    key: 'TestSiteCollectionUrl',
                }, 
                {
                    title: 'Email',
                    dataIndex: 'Email',
                    key: 'Email',
                }
        ];

        // rowSelection object indicates the need for row selection
        const rowSelection = {
            onChange: (selectedRowKeys, selectedRows) => {
                if(selectedRows[0].TenantName != undefined){
                    console.log(selectedRows[0].TenantName);
                    const options = { 
                        method: 'post'
                    };

                    adalApiFetch(fetch, "/Tenant/SetTenantActive?TenantName="+selectedRows[0].TenantName.toString(), options)
                        .then(response =>{
                        if(response.status === 200){
                            Notification(
                                'success',
                                'Tenant set to active',
                                ''
                                );
                        }else{
                            throw "error";
                        }
                        })
                        .catch(error => {
                        Notification(
                            'error',
                            'Tenant not activated',
                            error
                            );
                        console.error(error);
                    });
                }
            },
            getCheckboxProps: record => ({
                type: Radio
            }),
        };

        return (
            <Table rowSelection={rowSelection} columns={columns} dataSource={this.state.data} />
        );
    }
}

export default ListTenants;

And the code of the ActiveTenant component its also very simple

import React, { Component } from 'react';
import authAction from '../../redux/auth/actions';
import { adalApiFetch } from '../../adalConfig';

class ActiveTenant extends Component {
  constructor(props) {
    super(props);
    this.state = {
      tenant: ''
    };
  }

  fetchData = () => {
    adalApiFetch(fetch, "/Tenant/GetActiveTenant", {})
      .then(response => response.json())
      .then(responseJson => {
        if (!this.isCancelled) {
          this.setState({ tenant: responseJson.TenantName });
        }
      })
      .catch(error => {
        this.setState({ tenant: '' });
        console.error(error);
      });
  };


componentDidMount(){
    this.fetchData();
}

  render() {
    return (
      <div>You are using tenant: {this.state.tenant }</div>
    );
  }
}
export default ActiveTenant;

The problem is, if I have multiple tenants on my database registered and I set them to active, the server side action occurs, and the state is changed, however on the top right its still showing the old tenant as active, UNTIL I press F5 to refresh the browser.

How can I achieve this?

For the sake of complete understandment of my code I will need to paste below other components:

  1. TopBar which contains the active tenant

    import React, { Component } from "react";
    import { connect } from "react-redux";import { Layout } from "antd";
    import appActions from "../../redux/app/actions";
    import TopbarUser from "./topbarUser";
    import TopbarWrapper from "./topbar.style";
    import ActiveTenant from "./activetenant";
    import TopbarNotification from './topbarNotification';
    
    
    const { Header } = Layout;
    const { toggleCollapsed } = appActions;
    
    class Topbar extends Component {
      render() {
        const { toggleCollapsed, url, customizedTheme, locale } = this.props;
        const collapsed = this.props.collapsed && !this.props.openDrawer;
        const styling = {
          background: customizedTheme.backgroundColor,
          position: 'fixed',
          width: '100%',
          height: 70
        };
        return (
          <TopbarWrapper>
            <Header
              style={styling}
              className={
                collapsed ? "isomorphicTopbar collapsed" : "isomorphicTopbar"
              }
            >
              <div className="isoLeft">
                <button
                  className={
                    collapsed ? "triggerBtn menuCollapsed" : "triggerBtn menuOpen"
                  }
                  style={{ color: customizedTheme.textColor }}
                  onClick={toggleCollapsed}
                />
              </div>
    
              <ul className="isoRight">
                <li
                  onClick={() => this.setState({ selectedItem: 'notification' })}
                  className="isoNotify"
                >
                  <TopbarNotification locale={locale} />
                </li>
                <li>
                  <ActiveTenant />
                </li>
                <li
                  onClick={() => this.setState({ selectedItem: "user" })}
                  className="isoUser"
                >
                  <TopbarUser />
                  <div>{ process.env.uiversion}</div>
                </li>
              </ul>
            </Header>
          </TopbarWrapper>
        );
      }
    }
    
    export default connect(
      state => ({
        ...state.App.toJS(),
        locale: state.LanguageSwitcher.toJS().language.locale,
        customizedTheme: state.ThemeSwitcher.toJS().topbarTheme
      }),
      { toggleCollapsed }
    )(Topbar);
    

App.js which contains the top bar

import React, { Component } from "react";
import { connect } from "react-redux";
import { Layout, LocaleProvider } from "antd";
import { IntlProvider } from "react-intl";
import { Debounce } from "react-throttle";
import WindowResizeListener from "react-window-size-listener";
import { ThemeProvider } from "styled-components";
import authAction from "../../redux/auth/actions";
import appActions from "../../redux/app/actions";
import Sidebar from "../Sidebar/Sidebar";
import Topbar from "../Topbar/Topbar";
import AppRouter from "./AppRouter";
import { siteConfig } from "../../settings";
import themes from "../../settings/themes";
import { themeConfig } from "../../settings";
import AppHolder from "./commonStyle";
import "./global.css";
import { AppLocale } from "../../dashApp";
import ThemeSwitcher from "../../containers/ThemeSwitcher";



const { Content, Footer } = Layout;
const { logout } = authAction;
const { toggleAll } = appActions;
export class App extends Component {
  render() {
    const { url } = this.props.match;
    const { locale, selectedTheme, height } = this.props;
    const currentAppLocale = AppLocale[locale];
    return (
      <LocaleProvider locale={currentAppLocale.antd}>
      <IntlProvider
        locale={currentAppLocale.locale}
        messages={currentAppLocale.messages}
      >
      <ThemeProvider theme={themes[themeConfig.theme]}>
        <AppHolder>
          <Layout style={{ height: "100vh" }}>
            <Debounce time="1000" handler="onResize">
              <WindowResizeListener
                onResize={windowSize =>
                  this.props.toggleAll(
                    windowSize.windowWidth,
                    windowSize.windowHeight
                  )
                }
              />
            </Debounce>
            <Topbar url={url} />
            <Layout style={{ flexDirection: "row", overflowX: "hidden" }}>
              <Sidebar url={url} />
              <Layout
                className="isoContentMainLayout"
                style={{
                  height: height
                }}
              >
                <Content
                  className="isomorphicContent"
                  style={{
                    padding: "70px 0 0",
                    flexShrink: "0",
                    background: "#f1f3f6",
                    position: "relative"
                  }}
                >
                  <AppRouter url={url} />
                </Content>
                <Footer
                  style={{
                    background: "#ffffff",
                    textAlign: "center",
                    borderTop: "1px solid #ededed"
                  }}
                >
                  {siteConfig.footerText}
                </Footer>
              </Layout>
            </Layout>
            <ThemeSwitcher />
          </Layout>
        </AppHolder>
      </ThemeProvider>
      </IntlProvider>
      </LocaleProvider>
    );
  }
}

export default connect(
  state => ({
    auth: state.Auth,
    locale: state.LanguageSwitcher.toJS().language.locale,
    selectedTheme: state.ThemeSwitcher.toJS().changeThemes.themeName,
    height: state.App.toJS().height
  }),
  { logout, toggleAll }
)(App);

I think this should be enough to illustrate my question.

rrk
  • 15,677
  • 4
  • 29
  • 45
Luis Valencia
  • 32,619
  • 93
  • 286
  • 506
  • I don't really know if it can help you, I'm pretty new to React but when I want to access a component from another component I use `ref`, check the doc and tell me if it works for you : https://reactjs.org/docs/refs-and-the-dom.html :) – Bambou Feb 27 '19 at 10:23
  • It looks weird that you use Redux partially in your app. Why not use it everywhere, incl. `ListTenants` and `ActiveTenant`? – hindmost Feb 27 '19 at 10:24
  • I am not familiar with Redux, basically I took a template https://themeforest.net/item/isomorphic-react-redux-admin-dashboard/20262330, then I started adding my own components. – Luis Valencia Feb 27 '19 at 10:31
  • 1
    I'd suggest to study Redux more closely. It's really important in order to write well-designed apps. Read [this](https://redux.js.org/introduction/core-concepts) first. – hindmost Feb 27 '19 at 10:47

1 Answers1

2

You're not using redux correctly there. You need to keep somewhere in your redux state your active tenant; That information will be your single source of truth and will be shared among your components throughout the app. Every component that will need that information will be connected to that part of the state and won't need to hold an internal state for that information.

Actions, are where you would call your API to get your active tenant information or set a new tenant as active. These actions wil call reducers that will change your redux state (That includes your active tenant information) and those redux state changes will update your app components.

You should probably take some time to read or re-read the redux doc, it's short and well explained !

Saraband
  • 1,540
  • 10
  • 18