MuiThemeProvider: How to use different themes for different routes? - reactjs

I need to slightly change the theme depending on the current section of the site.
It seems that MuiThemeProvider only sets muiTheme on load; but it needs to be updated when the props change.
How can this be done?

You can try to put the theme in a wrapping component that keeps the theme in it's state. Using React's context this component exposes a function to child components to change the state.
import React, { Component } from 'react';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
import PropTypes from 'prop-types';
import theme from './theme';
import themeOther from './theme-other'
class Wrapper extends Component {
static childContextTypes = {
changeTheme: PropTypes.func
};
constructor(props) {
super(props);
this.state = {
muiTheme: getMuiTheme(theme)
};
}
getChildContext() {
return {changeTheme: this.changeTheme};
}
changeTheme = () => {
this.setState({
muiTheme: getMuiTheme(themeOther)
})
};
render() {
return (
<MuiThemeProvider muiTheme={this.state.muiTheme}>
{this.props.children}
</MuiThemeProvider>
)
}
}
export default Wrapper;
In some child component you can access the context and call the changeTheme function to set a different theme in the state. Make sure to include contextTypes else you can't access the function.
import React, { Component } from 'react';
import RaisedButton from 'material-ui/RaisedButton';
import PropTypes from 'prop-types'
class ChildComponent extends Component {
static contextTypes = {
changeTheme: PropTypes.func
};
render() {
return (
<RaisedButton
primary
onTouchTap={this.context.changeTheme}
label="Change The Theme"
/>
);
}
}
export default ChildComponent;
In the root of your app just render the wrapper.
ReactDOM.render(
<Wrapper>
<App />
</Wrapper>,
document.getElementById('root')
);
EDIT:
My first solution might have been abit too much. Since you are replacing the whole theme for the whole app. You can also use the MuiThemeProvider down the tree like so.
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import './index.css';
import inject from 'react-tap-event-plugin';
inject();
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
import theme from './theme';
ReactDOM.render(
<MuiThemeProvider muiTheme={getMuiTheme(theme)}>
<App />
</MuiThemeProvider>,
document.getElementById('root')
);
In a child component you can just use the MuiThemeProvider again and override some properties. Note that these changes will reflect on all the children inside this MuiThemeProvider.
import React, { Component } from 'react';
import RaisedButton from 'material-ui/RaisedButton';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
import theme from './theme';
import { green800, green900 } from 'material-ui/styles/colors';
const localTheme = getMuiTheme(Object.assign({}, theme, {
palette: {
primary1Color: green800,
primary2Color: green900
}
}));
class App extends Component {
render() {
return (
<div>
<RaisedButton
primary
label="Click"
/>
<MuiThemeProvider muiTheme={localTheme}>
<RaisedButton
primary
label="This button is now green"
/>
</MuiThemeProvider>
</div>
);
}
}
export default App;

Related

How to Pass in Store as a prop

I am currently having a problem getting store to be passed in as a prop and am wondering what to label a few things.
The current error is within create store, I'm unsure what to do with it.
I have tried other methods and only want to use the store method where I pass it in as a prop
import React from 'react';
import { MockGit } from './Constants';
import ExpansionPanelSummary from '#material-ui/core/ExpansionPanelSummary';
import ExpansionPanelDetails from '#material-ui/core/ExpansionPanelDetails';
import Typography from '#material-ui/core/Typography';
import ExpandMoreIcon from '#material-ui/icons/ExpandMore';
import ExpansionPanel from '#material-ui/core/ExpansionPanel';
import Button from '#material-ui/core/Button';
import TestAPI from './TestAPI';
import { displayGitData, userInfoURL, getDataSaga } from '../sagas/sagas';
import { createStore } from 'redux';
class GitData extends React.Component {
constructor(props) {
super(props);
}
render() {
const store = createStore(...); //this is what im unsure of.
const { store } = this.props;
return (
<ExpansionPanel>
<ExpansionPanelSummary expandIcon={<ExpandMoreIcon />}>
<Typography> {MockGit} </Typography>
</ExpansionPanelSummary>
<ExpansionPanelDetails>
{displayGitData()}
{userInfoURL()}
{getDataSaga()}
<TestAPI />
</ExpansionPanelDetails>
</ExpansionPanel>
);
}
}
export default GitData;
The goal is to get store passed in as a prop with no errors.
Any help would be great, Thanks!
You're doing it wrong, here's the recommended way to use React with Redux:
store.js
import { createStore } from 'redux';
export default createStore(...)
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import store from './store.js'
const App = () => (<h1>Hello from App</h1>);
ReactDOM.render(
<Provider store={store}><App/></Provider>
document.querySelector('#react-root')
);
You now have an app that is bound with the store.
The react-redux npm package allows also to bind component props to store dispatches and store state, example:
my-component.js
import React from 'react';
import { connect } from 'react-redux';
class MyComponent extends React.Component {
render() {
return (
<p>{this.props.hello}</p>
)
}
}
export default connect(state => ({hello: state.helloReducer.value}))(MyComponent)
For further tutorials, check the official docs of react-redux, or this good youtube playlist.

Material UI - outlined button - "Unexpected use of 'self' no-restricted-globals"

Trying to use an outlined button from material UI : https://github.com/mui-org/material-ui/blob/master/docs/src/pages/demos/buttons/OutlinedButtons.js
But get the error - "Unexpected use of 'self' no-restricted-globals"
And I don't have permissions to change it in the lodash.throttle/index.js file.
Is there any workaround for this that anyone knows of?? (It's literally just the sample code btw)
import React from 'react';
import PropTypes from 'prop-types';
import { withStyles } from '../node_modules/#material-ui/core/styles';
import Button from '../node_modules/#material-ui/core/Button';
const styles = theme => ({
button: {
margin: theme.spacing.unit,
},
input: {
display: 'none',
},
});
function OutlinedButtons(props) {
const {classes} = props;
return (
<div>
<Button variant="outlined" className={classes.button}>
Default
</Button>
</div>
);
}
OutlinedButtons.propTypes = {
classes: PropTypes.object.isRequired,
};
export default withStyles(styles)(OutlinedButtons);
After a request. App.js:
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import PropTypes from 'prop-types';
import { withStyles } from '#material-ui/core/styles';
import Button from '#material-ui/core/Button';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import UserGroup from './components/user_group';
import ButtonTest from './components/Button';
import OutlinedButtons from './components/floatingButton'
class App extends Component {
render() {
return (
<MuiThemeProvider>
<div className="App">
<header className="App-header">
{ OutlinedButtons }
</header>
</div>
</MuiThemeProvider>
);
}
}
export default App;
And index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
ReactDOM.render(<App />, document.getElementById('root'));
registerServiceWorker();

Children component gets props as undefined

I'm trying to pass props to my children components which are under the controller. I'm using redux and react-router for navigation. The problem is that everything is fine in the controller, it gets its initial props, but when I'm passing them to a child I have an undefined either the constructor or in render function. Here is my code:
import React, { Component } from 'react'
import { connect } from 'react-redux'
import moment from 'moment'
import LawsuitSchedule from '../components/LawsuitSchedule'
import LawsuitCalendar from '../components/LawsuitCalendar'
class LawsuitScheduleContainer extends Component {
constructor (props) {
super(props)
}
render () {
let {schedule} = this.props
console.log(schedule)
return (
<LawsuitCalendar initialDate={schedule.initialDate}
selectedDate={schedule.selectedDate}
scheduledDates={schedule.scheduledDates}/>,
<LawsuitSchedule/>
)
}
}
const mapStateToProps = state => ({
schedule: state.schedule,
})
export default connect(mapStateToProps)(LawsuitScheduleContainer)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import momentPropTypes from 'react-moment-proptypes'
import moment from 'moment'
import DatePicker from 'react-datepicker'
import 'react-datepicker/dist/react-datepicker.css'
import '../styles/lawsuitCalendar.css'
export default class LawsuitCalendar extends Component {
constructor (props) {
super(props)
console.log(props)
}
propTypes = {
selectedDate: momentPropTypes.momentString,
scheduledDates: PropTypes.array.isRequired,
}
handleChange = (date) => {
this.setState({
selectedDate: date,
})
}
render () {
let {selectedDate, scheduledDates} = this.props
let highlightWithRanges = [
{
'scheduled-date': scheduledDates,
},
]
return (
<DatePicker
inline
selected={selectedDate}
onChange={this.handleChange}
highlightDates={highlightWithRanges}
/>
)
}
}
The problem was in another component, which renders LawsuitCalendar too. I have no clue why it was displayed only once, but I have solved my problem with props -- I just didn't pass them. I've added it, maybe someone can answer why has that happened?
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { Grid, Row, Col } from 'react-bootstrap'
import { Link } from 'react-router-dom'
import ReactTable from 'react-table'
import matchSorter from 'match-sorter'
import LawsuitCalendar from '../components/LawsuitCalendar'
import '../styles/lawsuitGrid.css'
import data from '../utils/data.json'
export default class LawsuitSchedule extends Component {
render () {
return (
<Grid>
<Row className="show-grid">
<Col md={4}><LawsuitCalendar/></Col>
<Col md={8}>
<ReactTable data={data}
...
/>
</Col>
</Row>
</Grid>
)
}
}

reactjs mobx without decorators not working

I am trying to incorporate mobx with react. Since I spawned my application using create-react-app, I can't use decorators given by mobx.
Given that we can use mobx without decorators as per this documentation: https://mobxjs.github.io/mobx/best/decorators.html
Here's a component that I created:
import React, { Component } from 'react';
import observer from 'mobx-react';
export const TestComponent = observer(class TestComponent extends Component {
render() {
return <div>Just a test component!</div>
}
});
Here's a simple calling of the above component:
import React, { Component } from 'react';
import './App.css';
import Auth from './Auth'
import { TestComponent } from './Test'
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import AppBar from 'material-ui/AppBar';
import authStore from './stores/Store'
class App extends Component {
constructor(props) {
super(props);
this.state = {
}
}
render() {
return (
<div className="app">
<MuiThemeProvider>
<div>
<TestComponent store={authStore} />
</div>
</MuiThemeProvider>
</div>
);
}
}
export default App;
Now when I run the above component, I get error: Uncaught TypeError: (0 , _mobxReact2.default) is not a function(…) nothing get displays in console.
What am I doing wrong here?
Please use import {observer} from 'mobx-react';
N.B. note that decorators can be used with create-react-app by using custom-react-scripts, as explained here)

I cannot use material-ui components after update to material-ui#0.15.0-beta.1

I got this message in my console:
Failed Context Types: Required context muiTheme was not specified in
AppBar
AppBar.js:158 Uncaught TypeError: Cannot read property 'prepareStyles'
of undefined
I just have an AppBar in my Component
I think it should work but...
here my very simple code:
import React from 'react';
import {AppBar} from 'material-ui';
export class MyComponent extends React.Component {
render() {
return (
<div>
<AppBar
title="Title"
/>
</div>
);
}
}
thanks for helping...
With material-ui#0.15.0.beta-1 a few things were changed.
You can have a look on the link below for more details.
https://github.com/callemall/material-ui/blob/master/CHANGELOG.md
Therefore with those changes your code becomes:
import React from 'react';
import AppBar from 'material-ui/AppBar';
import baseTheme from 'material-ui/styles/baseThemes/lightBaseTheme';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
export class MyComponent extends React.Component {
getChildContext() {
return { muiTheme: getMuiTheme(baseTheme) };
}
render() {
return (
<div>
<AppBar
title="Title"
/>
</div>
);
}
}
MyComponent.childContextTypes = {
muiTheme: React.PropTypes.object.isRequired,
};
now in the 0.15.0 you can use muiThemeProvider:
...
import getMuiTheme from 'material-ui/styles/getMuiTheme';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import MyAwesomeReactComponent from './MyAwesomeReactComponent';
const App = () => (
<MuiThemeProvider muiTheme={getMuiTheme()}>
<MyAwesomeReactComponent />
</MuiThemeProvider>
)
...
So you do not have to provide context to childrens manualy.
More info in documentation.
Import MuiThemeProvider and then wrap the material-ui component AppBar with MuiThemeProvider.
import React, { Component } from 'react';
import AppBar from 'material-ui/AppBar';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import './App.css';
class App extends Component {
render() {
return (
<MuiThemeProvider>
<div>
<AppBar title = "Title" />
</div>
</MuiThemeProvider>
);
}
}
export default App;

Resources