Обновление состояния темы в реакции с использованием пользовательского интерфейса материала - PullRequest
0 голосов
/ 02 мая 2020

Я пытаюсь обновить состояние темы приложения, которое я создаю, в пользовательском интерфейсе с использованием реаги. Я пытаюсь создать переключатель, который переключается между светлым и темным режимом. Мой компонент приложения является компонентом на основе классов, поэтому я использую оператор материала UI useTheme().

Пока мой код выглядит так: Компонент приложения, в котором создается тема:

import React from 'react';
import { Router, Route, Switch, Redirect } from 'react-router-dom';
import { connect } from 'react-redux';

import { history } from '../_helpers';
import { alertActions } from '../_actions';
import { PrivateRoute } from '../_components';
import { HomePage } from '../HomePage';
import { IntroPage } from '../IntroPage';
import { LoginPage } from '../LoginPage';
import { RegisterPage } from '../RegisterPage';
import { SurveyPage, SurveryPage } from '../SurveyPage';
import { SideBar } from '../SideBar';
import { NewDiagnosisSplash } from '../NewDiagnosisSplashPage';
import { RecoveryPlanDashboard } from '../RecoveryPlanDashboard';
import { TodayExercises } from '../TodayExercises';
import { withTheme } from '@material-ui/core/styles';
import { createMuiTheme, ThemeProvider } from '@material-ui/core/styles';
import { blue, grey, white } from '@material-ui/core/colors';

import '../css/App.css';
import { Grid, Paper } from '@material-ui/core';



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

        history.listen((location, action) => {
            // clear alert on location change
            this.props.clearAlerts();
        });

        this.handleCheckBox = this.handleCheckBox.bind(this)
        this.theme = this.theme.bind(this)

        this.state = {
          checked: true,
          theme: null
        }

    }

    theme(){ 
    this.setState({
        theme: createMuiTheme({
            palette: {
              type: this.state.checked ? "dark": "light",
              primary: grey,
              secondary: blue,
            }, typography: {
                h3: {
                    fontWeight: 100,
                    color: blue
                }   
            }
        })
    })}

    componentWillMount(){
        this.theme()
    }

    componentDidMount(){
        console.log(this.state.theme)
    }

    handleCheckBox(e) {
        var oldTheme = {...this.state.theme}
        oldTheme.flag = true;
        this.setState({theme: createMuiTheme({
            palette: {
              type: this.state.checked ? "dark": "light",
              primary: grey,
              secondary: blue,
            }, typography: {
                h3: {
                    fontWeight: 100,
                    color: blue
                }   
            }
        })})
        this.setState({
          checked: !this.state.checked
        })
        console.log(this.state.checked)
    }

    render() {
        const { alert } = this.props;
        return (
            <ThemeProvider theme={this.state.theme}>
            <Paper style={{height: "100vh"}}>
            <Grid container direction="column" justify="center"
            alignItems="center" >
                {alert.message &&
                    <div className={`alert ${alert.type}`}>{alert.message}</div>
                }
                <Router history={history}>
                    <SideBar checked={this.state.checked} changed={this.handleCheckBox}>
                    </SideBar>
                    <Grid item xs={false} sm={4} />
                    <Grid item xs={12} sm={4}>
                        <Switch>
                            <PrivateRoute exact path="/" component={HomePage} />
                            <Route path="/intro" component={IntroPage} />
                            <Route path="/login" component={LoginPage} />
                            <Route path="/register" component={RegisterPage} />
                            <Route path="/survey" component={SurveryPage} />
                            <Route path="/new-diagnosis" component={NewDiagnosisSplash} />
                            <Route path="/recovery-plans" component={RecoveryPlanDashboard} />
                            <Route path="/today-exercises" component={TodayExercises} />
                            <Redirect from="*" to="/" />
                        </Switch>
                    </Grid>
                    <Grid item xs={false} sm={4} />
                </Router>
            </Grid>
            </Paper>
            </ThemeProvider>

        );
    }
}

function mapState(state) {
    const { alert } = state;
    return { alert };
}

const actionCreators = {
    clearAlerts: alertActions.clear
};

const connectedApp = connect(mapState, actionCreators)(App);
const withThemesObj = withTheme(connectedApp)
export { withThemesObj as App };

И это боковая панель с кнопкой:

import { connect } from 'react-redux';

import React, { useDebugValue, useEffect } from 'react';
import clsx from 'clsx';
import { makeStyles, useTheme } from '@material-ui/core/styles';
import Drawer from '@material-ui/core/Drawer';
import AppBar from '@material-ui/core/AppBar';
import Toolbar from '@material-ui/core/Toolbar';
import CssBaseline from '@material-ui/core/CssBaseline';
import List from '@material-ui/core/List';
import Typography from '@material-ui/core/Typography';
import Divider from '@material-ui/core/Divider';
import IconButton from '@material-ui/core/IconButton';
import MenuIcon from '@material-ui/icons/Menu';
import ChevronLeftIcon from '@material-ui/icons/ChevronLeft';
import ChevronRightIcon from '@material-ui/icons/ChevronRight';
import ListItem from '@material-ui/core/ListItem';
import ListItemIcon from '@material-ui/core/ListItemIcon';
import ListItemText from '@material-ui/core/ListItemText';
import { Link } from 'react-router-dom';
import { userActions } from '../_actions';
import PreviousDiagnosis from '../assets/imgs/PreviousDiagnosis.svg'
import Account from '../assets/imgs/Account.svg'
import StartDiagnosis from '../assets/imgs/StartDiagnosis.svg'
import FitnessIcon from '../assets/imgs/Fitness.svg'
import SettingsIcon from '../assets/imgs/Settings.svg'
import AboutIcon from '../assets/imgs/About.svg'
import LegalIcon from '../assets/imgs/Legal.svg'
import SignOutIcon from '../assets/imgs/SignOut.svg'
import Switch from '@material-ui/core/Switch';

console.log(userActions.getAll)
const drawerWidth = 240;


const useStyles = makeStyles((theme) => ({
  root: {
    display: 'flex',
  },
  appBar: {
    transition: theme.transitions.create(['margin', 'width'], {
      easing: theme.transitions.easing.sharp,
      duration: theme.transitions.duration.leavingScreen,
    }),
  },
  appBarShift: {
    width: `calc(100% - ${drawerWidth}px)`,
    transition: theme.transitions.create(['margin', 'width'], {
      easing: theme.transitions.easing.easeOut,
      duration: theme.transitions.duration.enteringScreen,
    }),
    marginRight: drawerWidth,
  },
  title: {
    flexGrow: 1,
    color: theme.palette.text.primary
  },
  hide: {
    display: 'none',
  },
  drawer: {
    width: drawerWidth,
    flexShrink: 0,
  },
  drawerPaper: {
    width: drawerWidth,
  },
  drawerHeader: {
    display: 'flex',
    alignItems: 'center',
    padding: theme.spacing(0, 1),
    // necessary for content to be below app bar
    ...theme.mixins.toolbar,
    justifyContent: 'flex-start',
  },
  content: {
    flexGrow: 1,
    padding: theme.spacing(3),
    transition: theme.transitions.create('margin', {
      easing: theme.transitions.easing.sharp,
      duration: theme.transitions.duration.leavingScreen,
    }),
    marginRight: -drawerWidth,
  },
  contentShift: {
    transition: theme.transitions.create('margin', {
      easing: theme.transitions.easing.easeOut,
      duration: theme.transitions.duration.enteringScreen,
    }),
    marginRight: 0,
  },
}));

function PersistentDrawerRight(props) {
  const classes = useStyles();
  const theme = useTheme();
  const [open, setOpen] = React.useState(false);
  const { checked, changed } = props;


  useEffect(()=>{
    //props.getAll()
  })

  const handleDrawerOpen = () => {
    setOpen(true);
  };

  const handleDrawerClose = () => {
    setOpen(false);
  };

  const helloStyle = {
    fontWeight: 200
  }

  const loginText = () => {
    if(props.user === undefined){
      return "Welcome to Sina Tech"
    } if (props.user.firstName){
      return props.user.firstName
    }
  }


  return (
    <div className={classes.root}>
      <CssBaseline />
      <AppBar
        position="fixed"
        className={clsx(classes.appBar, {
          [classes.appBarShift]: open,
        })}

      >
        <Toolbar>
          <Typography variant="h5" noWrap className={classes.title} color="primary">
            <Link color="primary" underline="none" variant="inherit" to={'/'}><span style={helloStyle}>Hello,</span> {loginText()}</Link>
          </Typography>
          <IconButton
            color="inherit"
            aria-label="open drawer"
            edge="end"
            onClick={handleDrawerOpen}
            className={clsx(open && classes.hide)}
          >
            <MenuIcon />
          </IconButton>
        </Toolbar>
      </AppBar>
      <main
        className={clsx(classes.content, {
          [classes.contentShift]: open,
        })}
      >
        <div className={classes.drawerHeader} />
      </main>
      <Drawer
        className={classes.drawer}
        variant="persistent"
        anchor="right"
        open={open}
        classes={{
          paper: classes.drawerPaper,
        }}
      >
        <div className={classes.drawerHeader}>
          <IconButton onClick={handleDrawerClose}>
            {theme.direction === 'rtl' ? <ChevronLeftIcon /> : <ChevronRightIcon />}
          </IconButton>
        </div>
        <Divider />
        <List>
            <Link to={'/survey'}>
              <ListItem button key={"New Diagnosis"}>
                <ListItemIcon><StartDiagnosis /></ListItemIcon>
                <ListItemText>Start Diagnosis</ListItemText>
              </ListItem>
            </Link>
            <Link to={'/survey'}>
              <ListItem button key={"Continue Diagnosis"}>
                <ListItemIcon><Account /></ListItemIcon>
                <ListItemText>Account</ListItemText>
              </ListItem>
            </Link>
            <Link to={'/survey'}>
              <ListItem button key={"Previous Diagnosis"}>
                <ListItemIcon><PreviousDiagnosis /></ListItemIcon>
                <ListItemText>Previous Diagnosis</ListItemText>
              </ListItem>
            </Link>
            <Link to={'/recovery-plans'}>
              <ListItem button key={"Recovery Plans"}>
                <ListItemIcon><FitnessIcon /></ListItemIcon>
                <ListItemText>Recovery Plans</ListItemText>
              </ListItem>
            </Link>
            <Link to={'/survey'}>
              <ListItem button key={"Settings"}>
                <ListItemIcon><SettingsIcon /></ListItemIcon>
                <ListItemText>Settings</ListItemText>
              </ListItem>
            </Link>
            <Link to={'/survey'}>
              <ListItem button key={"About Us"}>
                <ListItemIcon><AboutIcon /></ListItemIcon>
                <ListItemText>About Us</ListItemText>
              </ListItem>
            </Link>
            <Link to={'/survey'}>
              <ListItem button key={"Legal"}>
                <ListItemIcon><LegalIcon /></ListItemIcon>
                <ListItemText>Legal</ListItemText>
              </ListItem>
            </Link>
            <Link to="/login">
              <ListItem button key={"Sign Out"}>
              <ListItemIcon><SignOutIcon /></ListItemIcon>                 
                Sign Out
              </ListItem>
            </Link>
              <Switch
                        checked={props.checked}
                        onChange={props.changed}
                        name="checkedA"
                        inputProps={{ 'aria-label': 'secondary checkbox' }}
                    />
        </List>
      </Drawer>
    </div>
  );
}

function mapState(state) {
  const { users, authentication } = state;
  const { user } = authentication;
  return { user, users };
}

const actionCreators = {
  getUsers: userActions.getAll,
  deleteUser: userActions.delete
}

const connectedSideBar = connect(mapState, actionCreators)(PersistentDrawerRight);
export { connectedSideBar as SideBar };

Моя проблема заключается в том, что мне нужно повторно инициализировать состояние здесь:

    constructor(props) {
        super(props);

        history.listen((location, action) => {
            // clear alert on location change
            this.props.clearAlerts();
        });

        this.handleCheckBox = this.handleCheckBox.bind(this)
        this.theme = this.theme.bind(this)

        this.state = {
          checked: true,
          theme: null
        }

    }

    theme(){ 
    this.setState({
        theme: createMuiTheme({
            palette: {
              type: this.state.checked ? "dark": "light",
              primary: grey,
              secondary: blue,
            }, typography: {
                h3: {
                    fontWeight: 100,
                    color: blue
                }   
            }
        })
    })}

    componentWillMount(){
        this.theme()
    }

    componentDidMount(){
        console.log(this.state.theme)
    }

    handleCheckBox(e) {
        var oldTheme = {...this.state.theme}
        oldTheme.flag = true;
        this.setState({theme: createMuiTheme({
            palette: {
              type: this.state.checked ? "dark": "light",
              primary: grey,
              secondary: blue,
            }, typography: {
                h3: {
                    fontWeight: 100,
                    color: blue
                }   
            }
        })})
        this.setState({
          checked: !this.state.checked
        })
        console.log(this.state.checked)
    }

функциональность работает, как и ожидалось, но это очень грязный код, требующий повторной инициализации состояния, есть идеи, как я могу это исправить?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...