Enhancing from Component in React with Material-UI - javascript

I am using React and Material-UI. Is there any way to export a class estended from React.Component? I want to use some React variables like state. If this is not possible, how can I use state?
Actual code (works):
import React from 'react';
import { Typography } from '#material-ui/core';
import { makeStyles } from '#material-ui/styles';
const styles = makeStyles(() => ({
style1: {
fontSize: '12px'
}
}));
const MyComponent = () => {
const classes = styles();
return(
<Typography className={classes.style1}>Hello World</Typography>
);
}
export default MyComponent;
What I am looking for:
import React, { Component } from 'react';
import { Typography } from '#material-ui/core';
import { makeStyles } from '#material-ui/styles';
export default class MyComponent extends Component {
constructor(props){
super(props);
this.classes = makeStyles(() => ({
style1: {
fontSize: '12px'
}
}));
}
render() {
return(
<Typography className={this.classes.style1}>Hello World</Typography>
);
}
}

You are using makeStyles(), which is used when your component is a functional component. makeStyles() is a Hooks API.
If you are using the Class component, then you must be using the HOC variant, which is withStyles
Example taken from here:
import React from 'react';
import { withStyles } from '#material-ui/core/styles';
const styles = {
root: {
backgroundColor: 'red',
},
};
function MyComponent(props) {
return <div className={props.classes.root} />;
}
export default withStyles(styles)(MyComponent);
withStyles() can be used for both functional and class components unlike makeStyles(), which can only be used for functional components.
You can also use decorator syntax for HOC variant like here. But you need to use this babel plugin like mentioned in the official material-ui docs:
import React from 'react';
import { withStyles } from '#material-ui/core/styles';
const styles = {
root: {
backgroundColor: 'red',
},
};
#withStyles(styles)
class MyComponent extends React.Component {
render () {
return <div className={this.props.classes.root} />;
}
}
export default MyComponent

Related

How to test a react component with props?

I need to test a react components with props mounts ok and renders its content such as paras and divs correctly. My code can be found below or in this sandbox
I tried testing it with a default prop but that didn't work.
import React from 'react';
import test from 'tape';
import {mount} from 'enzyme';
test('testing', t => {
t.doesNotThrow(() => {
wrapper = mount(<App2 txt={ok}/>);
}, 'Should mount');
t.end();
});
And this is my component with props.
import React, { Component } from 'react';
import { render } from 'react-dom';
import Hello from './Hello';
import './style.css';
import App from './index'
export default class App2 extends Component {
constructor() {
super();
this.state = {
name: 'React'
};
}
render() {
const {txt}=this.props
return (
<div>
<p>hi {txt}</p>
</div>
);
}
}
And the outer component supplying the prop.
import React, { Component } from 'react';
import { render } from 'react-dom';
import Hello from './Hello';
import './style.css';
import App2 from './app2'
class App extends Component {
constructor() {
super();
this.state = {
name: 'React'
};
}
render() {
return (
<div>
<Hello name={this.state.name} />
<p>
Start editing to see some magic happen :)
</p>
<App2 txt={this.state.name}/>
</div>
);
}
}
render(<App />, document.getElementById('root'));
So you would do something like providing the properties yourself and ensuring that it renders with them:
test('test your component', () => {
const wrapper = mount(<App2 txt={'michaelangelo'} />);
expect(wrapper.find('p').text()).toEqual('hi michaelangelo');
});
You shouldn't worry about testing the and html elements like that, but rather the props that you pass and that they render in the right place i.e., in the p tag

How to implement Context API in React Native

I just start looking for changing theme globally, and found Context can do that,
but I've a problem to implement the example code to my react native project,
I've tried this code:
//themeContext.js
const themes = {
light: {
foreground: '#000000',
background: '#eeeeee',
},
dark: {
foreground: '#ffffff',
background: '#222222',
},
};
export const ThemeContext = React.createContext({
theme: themes.dark,
toggleTheme: () => {},
})
//App.js
import React, { Component } from 'react';
import {InitialScreen} from './routes/routes';
import { ThemeContext } from './Component/themeContext';
export default class App extends Component {
constructor(props) {
super(props);
this.state={
theme:themes.light,
toggleTheme:this.toggleTheme
}
this.toggleTheme=()=>{
this.setState(state=>({
theme:state.theme === themes.dark ? themes.light : themes.dark
}))
}
}
render() {
console.disableYellowBox = true;
return (
<ThemeContext.Provider value={this.state}>
//this is Login.js
<InitialScreen/>
</ThemeContext.Provider>
);
}
}
//Login.js
import React from 'react';
import { Text, TouchableOpacity, View } from 'react-native';
import { ThemeContext } from '../Component/themeContext';
export default class Login extends Component {
render() {
return (
<ThemeContext.Consumer>
{({theme, toggleTheme})=>{
<View style={{backgroundColor:theme.background}}>
<Text>{this.state}</Text>
</View>
}}
</ThemeContext.Consumer>
);
}
}
but i have an error Can't find variable: Component, i don't know where should i put import React from 'react'; cause i think I've add Component var in app.js and login.js
any help would be appreciate
Replace next string in the top of your Login.js instead of
import React from 'react';
with
import React, { Component } from 'react';
Another way is to replace
export default class Login extends Component {
}
with
export default class Login extends React.Component {
}
In App.js updated your App component class defintion by replacing Component with React.Component as shown:
export default class App extends React.Component {
/* existing component code */
}
Make the same change in Login.js as well:
export default class Login extends React.Component {
/* existing component code */
}
These changes will cause the Login and App components to extend from the Component class as defined on the React object exported from 'react'.
Your problem in themeContext.js file
you use createContext() but you don't import React so you will get can't find React
it's should be like this
import React from 'react';
export const themes = {
light: {
foreground: '#000000',
background: '#eeeeee',
},
dark: {
foreground: '#ffffff',
background: '#222222',
},
};
export const ThemeContext = React.createContext({
theme: themes.dark,
toggleTheme: () => {},
});
And in Login.js
import React,{Component} from 'react';

undefined is not an object '_this3.props.navigation()' error in react native

running my react app gives error in navigationOptions() but it is working fine in render() function
App.js
import React, { Component } from 'react';
import { AppRegistry, View } from 'react-native';
import AppNavigator from './routs.js'
class App extends Component {
render() {
return (
<AppNavigator />
)
}
}
export default App
routs.js
import React from 'react'
import Home from './home.js'
import Phone from './phone.js'
import PhoneScreen from './phoneScreen.js'
import {createStackNavigator, createAppContainer} from 'react-navigation';
const MainNavigator = createStackNavigator({
home: {screen: Home},
add: {screen: Phone},
userScreen: {screen: PhoneScreen},
});
const AppNavigator = createAppContainer(MainNavigator);
export default AppNavigator;
home.js
import React from 'react'
import { TouchableOpacity, Text, View, TouchableHighlight, StyleSheet, Button } from 'react-native';
import { Actions } from 'react-native-router-flux';
import {AsyncStorage} from 'react-native';
class Home extends React.Component {
constructor(props) {
super(props);
}
static navigationOptions = {
headerTitle: 'Contacts',
headerRight: (
<Button
onPress={() => this.props.navigation.navigate('add')}
title="create new contact"
color="#000000"
size="20"
/>
),
};
}
export default Home;
"undefind is not an object(evaluating '_this3.props.navigation')"
please give solution
From the React Navigation Docs:
The binding of this in navigationOptions is not the HomeScreen
instance, so you can't call setState or any instance methods on it.
This is pretty important because it's extremely common to want the
buttons in your header to interact with the screen that the header
belongs to.
So, as you can see, this is not what you think it is in this case. Here's more from the docs detailing a working example:
class HomeScreen extends React.Component {
static navigationOptions = ({ navigation }) => {
return {
headerTitle: <LogoTitle />,
headerRight: (
<Button
onPress={navigation.getParam('increaseCount')}
title="+1"
color="#fff"
/>
),
};
};
componentDidMount() {
this.props.navigation.setParams({ increaseCount: this._increaseCount });
}
state = {
count: 0,
};
_increaseCount = () => {
this.setState({ count: this.state.count + 1 });
};
/* later in the render function we display the count */
}
As you can see, changing navigationOptions from an object into a function allows you to grab the navigation reference. From there you can successfully navigate.

React and Material-Ui define class in .js and pass it as string to a component

Im trying to define a class inside my .js file, so i can make use of material-uis theme object and pass it as a string to a component as the components prop only accepts strings. The React-Dropzone import only accepts a string as a parameter and not a class object.
codesandbox:
https://codesandbox.io/s/x74qvqxww4
or:
import React, { Fragment } from "react";
import Dropzone from "react-dropzone";
import { withStyles } from "#material-ui/core/styles";
const styles = theme => ({
green: {
color: "blue"
}
});
function CustomDropzone(props) {
return (
<Fragment>
<Dropzone acceptClassName="dropzoneAccept" />
<div className={props.classes.green}>
Thats how i appy styles normally
</div>
</Fragment>
);
}
export default withStyles(styles, { withTheme: true })(CustomDropzone);
How can i achieve it? Importing a .css file works but then the styles in my projects arent consistent.
Thanks for any help in advance!
All you would need to do is to declare the class like so:
import React, { Fragment } from "react";
import Dropzone from "react-dropzone";
import { withStyles } from "#material-ui/core/styles";
const styles = theme => ({
green: {
color: "blue"
}
});
class CustomDropzone extends React.Component {
render() {
return (
<Fragment>
<Dropzone acceptClassName="dropzoneAccept" />
<div className={this.props.classes.green}>
Thats how i appy styles normally
</div>
</Fragment>
);
}
}
export default withStyles(styles, { withTheme: true })(CustomDropzone);

Why Material-UI Appbar onLeftIconButtonTouchTap is not work?

Im studying React-Redux, Material-UI.
Now, Im trying to create Sample App, but not work.
I dont know how to improve my code.
I want to open Drawer , when Material-UI AppBar onLeftIconButtonTouchTap is clicked.
I cant bind my Action to Component, I think.
When following code is running, not fire onLeftIconButtonTouchTap event.
And when I change openDrawer to openDrawer(), JS error 'openDrawer is not a function' is found on Chrome Dev tool.
Header.jsx as a Component
import React, { PropTypes } from 'react';
import AppBar from 'material-ui/AppBar';
import Drawer from 'material-ui/Drawer';
const Header = ({
openDrawer,
open
}) => (
<div>
<AppBar
title='sample'
onLeftIconButtonTouchTap = {() => openDrawer}
/>
<Drawer
docked={false}
open={open}
/>
</div>
)
Header.PropTypes = {
openDrawer: PropTypes.func.isRequired,
open: PropTypes.bool.isRequired
}
export default Header;
HeaderContainer.jsx as a Container
import React from 'react';
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux';
import { header } from '../actions'
import Header from '../components/Header';
const mapStateToProps = (state) => ({open});
const mapDispatchToProps = (dispatch) => (
{openDrawer: bindActionCreators(header, dispatch)}
);
const HeaderContainer = connect(
mapStateToProps,
mapDispatchToProps
)(Header);
export default HeaderContainer;
App.jsx as a RootComponent
import React, { Component, PropTypes } from 'react';
import Header from '../components/Header';
import injectTapEventPlugin from "react-tap-event-plugin";
import baseTheme from 'material-ui/styles/baseThemes/lightBaseTheme';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
injectTapEventPlugin();
class App extends Component {
constructor(props) {
super(props);
}
getChildContext() {
return { muiTheme: getMuiTheme(baseTheme) };
}
render() {
return (
<div>
<Header />
{this.props.children}
</div>
);
}
};
App.childContextTypes = {
muiTheme: React.PropTypes.object.isRequired,
};
export default App;
Thanks in advance.
You are not binding the function correctly. You need to update your code to
<AppBar
title='sample'
onLeftIconButtonTouchTap = { openDrawer.bind(this) }
/>
More about .bind() method here: Use of the JavaScript 'bind' method

Categories