Reactjs with Rails, remove duplicated createMuiTheme - ruby-on-rails

the code below is one of my component.
i am creating this with Ruby on Rails framework, with react_rails gem and webpacker, experimenting on Material UI.
as you can see, i am changing the Material UI default font theme with my own choice of font. below code is a success.
my question is, do i have to repeat this step for all my component?
importing createMuiTheme, stating the theme const, and wrapping <MuiThemeProvider /> in every render?
is there a single way to do this universally, without repeating in all component?
thanks for the advice.
import React from 'react';
import PropTypes from 'prop-types';
import Card from '#material-ui/core/Card';
import CardActions from '#material-ui/core/CardActions';
import CardContent from '#material-ui/core/CardContent';
import Button from '#material-ui/core/Button';
import Popover from '#material-ui/core/Popover';
import Typography from '#material-ui/core/Typography';
import List from '#material-ui/core/List';
import ListItem from '#material-ui/core/ListItem';
import ListItemText from '#material-ui/core/ListItemText';
import Avatar from '#material-ui/core/Avatar';
import EmailIcon from '#material-ui/icons/Email';
import HomeIcon from '#material-ui/icons/Home';
import PersonIcon from '#material-ui/icons/Person';
import { MuiThemeProvider, createMuiTheme, withStyles } from '#material-ui/core/styles';
const theme = createMuiTheme({
typography: {
fontFamily: 'Bebas',
},
});
export class SimpleCard extends React.Component {
render () {
return (
<div >
<MuiThemeProvider theme={theme}>
<Card raised="true">
<CardContent >
<List>
<ListItem>
<Avatar>
<EmailIcon />
</Avatar>
<ListItemText primary="Email" secondary={this.props.order.order_mail} />
</ListItem>
</List>
</CardContent>
</Card>
</MuiThemeProvider>
</div>
);
}
}
export default withStyles(styles)(SimpleCard);

Did you try wrapping the MuiThemeProvider around the entire site/app? This is what I do in React.js. I set up my theme in the root file and wrap it around the entire component

import React, { Component } from "react";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
// Components
import Navbar from "./components/layout/Navbar";
import Footer from "./components/layout/Footer";
import Login from "./components/auth/Login";
import Dashboard from "./components/dashboard/Dashboard";
// Styles
import "./stylesheets/App.css";
import {
MuiThemeProvider,
createMuiTheme,
withTheme
} from "#material-ui/core/styles";
import { grey } from "#material-ui/core/colors";
import { withStyles } from "#material-ui/core";
const theme = createMuiTheme({
overrides: {
MuiGrid: {
container: {
width: "100%",
margin: "0"
}
}
},
palette: {
primary: {
light: "#c146b1",
main: "#8e0081",
dark: "#5c0054",
contrastText: "#ffffff"
},
secondary: {
light: "#6bffff",
main: "#00eae3",
dark: "#00b7b1",
contrastText: "#000000"
}
}
});
const drawerWidth = 240;
const styles = theme => ({
app: {
backgroundColor: grey[200]
},
drawerOpen: {
marginLeft: 0
},
drawerClosed: {
marginLeft: -drawerWidth
}
});
class App extends Component {
constructor() {
super();
this.state = {
navOpen: false
};
}
toggleDrawer = () => {
this.setState({
navOpen: !this.state.navOpen
});
};
render() {
const { classes } = this.props;
return (
<MuiThemeProvider theme={theme}>
<div className={classes.app}>
<Navbar
toggleDrawer={this.toggleDrawer}
navOpen={this.state.navOpen}
/>
<Route exact path="/" component={Dashboard} />
<Route exact path="/register" component={PatientRegister} />
<Route exact path="/login" component={Login} />
<Footer />
</div>
</Router>
</MuiThemeProvider>
);
}
}
export default withTheme(theme)(withStyles(styles)(App));
This is an example of my component that will be rendered in the root div (aka the entire application). Notice how wraps the entire app? I stripped a lot out to make it simpler to understand, but if you are using Redux (which is awesome) then I would recommend having that as your outer wrapper, and the rest inside of that. In other words:
<Provider store={store}>
<MuiThemeProvider theme={theme}>
<div class="App">
// Your App Here
</div>
</MuiThemeProvider>
</Provider>

Related

EXPO app is blink at iOS when it is appeared to front but Android is no problem. It was created automatically by EXPO (react navigation)

I have created my app with Expo(React Navigation 5.0) and changed "createBottomTabNavigator" to "createMaterialBottomTabNavigator". But When it is at front as soon as it was at back, it is blink.
This is the captured screen of terminal for my initiating app.
creating my app by EXPO
This is the code which is only changed by me.
import { createMaterialBottomTabNavigator } from '#react-navigation/material-bottom-tabs';
const BottomTab = createMaterialBottomTabNavigator<BottomTabParamList>();
The rest of code is automatically made by "expo init my-app"
This is App.tsx
import { StatusBar } from 'expo-status-bar';
import React from 'react';
import { SafeAreaProvider } from 'react-native-safe-area-context';
import useCachedResources from './hooks/useCachedResources';
import useColorScheme from './hooks/useColorScheme';
import Navigation from './navigation';
export default function App() {
const isLoadingComplete = useCachedResources();
const colorScheme = useColorScheme();
if (!isLoadingComplete) {
return null;
} else {
return (
<SafeAreaProvider>
<Navigation colorScheme={colorScheme} />
<StatusBar />
</SafeAreaProvider>
);
}
}
and this is index.tsx
import { NavigationContainer, DefaultTheme, DarkTheme } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
import * as React from 'react';
import { ColorSchemeName } from 'react-native';
import NotFoundScreen from '../screens/NotFoundScreen';
import { RootStackParamList } from '../types';
import BottomTabNavigator from './BottomTabNavigator';
import LinkingConfiguration from './LinkingConfiguration';
// If you are not familiar with React Navigation, we recommend going through the
// "Fundamentals" guide: https://reactnavigation.org/docs/getting-started
export default function Navigation({ colorScheme }: { colorScheme: ColorSchemeName }) {
return (
<NavigationContainer
linking={LinkingConfiguration}
theme={colorScheme === 'dark' ? DarkTheme : DefaultTheme}>
<RootNavigator />
</NavigationContainer>
);
}
// A root stack navigator is often used for displaying modals on top of all other content
// Read more here: https://reactnavigation.org/docs/modal
const Stack = createStackNavigator<RootStackParamList>();
function RootNavigator() {
return (
<Stack.Navigator screenOptions={{ headerShown: false }}>
<Stack.Screen name="Root" component={BottomTabNavigator} />
<Stack.Screen name="NotFound" component={NotFoundScreen} options={{ title: 'Oops!' }} />
</Stack.Navigator>
);
}
This is blinking captured video
I hope anyone can help me
It is a known bug in react-native.
https://github.com/facebook/react-native/issues/28525
Try to replace useColorScheme hook (hooks/useColorScheme.ts) with the following code:
import { Appearance, ColorSchemeName } from 'react-native';
import { useEffect, useRef, useState } from 'react';
export default function useColorScheme(delay = 500): NonNullable<ColorSchemeName> {
const [colorScheme, setColorScheme] = useState(Appearance.getColorScheme());
let timeout = useRef<NodeJS.Timeout | null>(null).current;
useEffect(() => {
Appearance.addChangeListener(onColorSchemeChange);
return () => {
resetCurrentTimeout();
Appearance.removeChangeListener(onColorSchemeChange);
};
}, []);
function onColorSchemeChange(preferences: Appearance.AppearancePreferences) {
resetCurrentTimeout();
timeout = setTimeout(() => {
setColorScheme(preferences.colorScheme);
}, delay);
}
function resetCurrentTimeout() {
if (timeout) {
clearTimeout(timeout);
}
}
return colorScheme as NonNullable<ColorSchemeName>;
}

react-hook-form FormContext default values problem

Trying to use react-hook-form FormContext.
I'm supplying deafultValues object in useForm hook. But couldn't manage to populate my component, simple textfield, with the default value in by Bottom.tsx component.
sandbox
Not sure if you got this working, but I was able to get it working by spreading the methods and using Controller for both TextFields. Also, you were importing control from RHF but it's actually returned from useFormContext()
import React from "react";
import Bottom from "./Bottom";
import { Grid } from "#material-ui/core";
import { useForm, FormContext } from "react-hook-form";
const App = () => {
const defaultValues = {
car: "AUDI",
city: "Tokyo"
};
const { ...methods } = useForm({ defaultValues });
return (
<FormContext {...methods}>
<Grid container direction="column">
<Grid item>
<Bottom />
</Grid>
</Grid>
</FormContext>
);
};
export default App;
import React from "react";
import { TextField } from "#material-ui/core";
import { useFormContext, Controller } from "react-hook-form";
interface BottomProps {}
const Bottom: React.FunctionComponent<BottomProps> = (props: BottomProps) => {
const { register, control } = useFormContext();
return (
<>
<Controller
name="city"
control={control}
as={
<TextField
ref={register}
style={{ margin: 20 }}
variant="outlined"
size="small"
label="City"
/>
}
/>
<Controller
name="car"
control={control}
as={
<TextField
ref={register}
style={{ margin: 20 }}
variant="outlined"
size="small"
label="Car"
/>
}
/>
</>
);
};
export default Bottom;
https://codesandbox.io/s/dreamy-goldwasser-so349?file=/src/App.tsx

How to implement react-native-dark-mode in ios

Hi all i want to try implement react-native-dark-mode but not worked in my project.
"react-native": "0.61.5"
I Already try like this :
import { useDarkMode } from 'react-native-dark-mode'
export default class Login extends Component {
render(){
const isDarkMode = useDarkMode() // i think this make error
return(
<View style={{ backgroundColor: isDarkMode ? 'black' : 'white' }}></View>
)
}
}
This my error
error-output
any solutions?
In your scenario react hooks can only be used inside the functional components
Example of functional component usage:
import { useDarkMode } from 'react-native-dark-mode'
function Component() {
const isDarkMode = useDarkMode()
return <View style={{ backgroundColor: isDarkMode ? 'black' : 'white' }} />
}
Example of class component usage:
You can play around with DarkModeContext. Just make sure to wrap your application in a DarkModeProvider with no props to avoid getting a value of current.
1 - Setup context provider for the app.
// App.js or top of the hierarchy in your app
import React, {Component} from 'react';
import {DarkModeProvider} from 'react-native-dark-mode';
export default class App extends Component {
render() {
return (
<DarkModeProvider>
<YourApp />
</DarkModeProvider>
);
}
}
2 - Use the context with contextType or context consumer.
// class based component with contextType
import React, {Component} from 'react';
import {Text} from 'react-native';
import {DarkModeContext} from 'react-native-dark-mode';
export default class HelloWorldText extends Component {
static contextType = DarkModeContext;
render() {
const isDarkMode = this.context === 'dark';
return (
<Text style={{color: isDarkMode ? '#ffffff' : '#000000'}}>
{this.props.children}
</Text>
);
}
}
3 - Final class based component
// class based component with context consumer
import React, {Component} from 'react';
import {Text} from 'react-native';
import {DarkModeContext} from 'react-native-dark-mode';
export default class HelloWorldText extends Component {
render() {
return (
<DarkModeContext.Consumer>
{mode => (
<Text style={{color: mode === 'dark' ? '#ffffff' : '#000000'}}>
{this.props.children}
</Text>
)}
</DarkModeContext.Consumer>
);
}
}
If you want to know about the context, you can find more detail in context page. It is really useful feature for both, class and function components.

React Native error the component must be a react component

So i am new to react native and JS in general, i have a huge background in native mobile development and i want to know more about Web Apps. So i try to begin with react native to experience that.
I wanted to do a side menu using createDrawerNavigator, so i created the following component :
// code for the menu
import React from 'react';
import { Platform } from 'react-native';
import { createStackNavigator, createDrawerNavigator, createAppContainer, DrawerActions } from "react-navigation";
import HomeScreen from '../screens/HomeScreen';
import LinksScreen from '../screens/LinksScreen';
import SettingsScreen from '../screens/SettingsScreen';
const App = createDrawerNavigator({
HomeScreen: {
screen: HomeScreen
},
LinksScreen: {
screen: LinksScreen
},
SettingsScreen: {
screen: SettingsScreen
}
},
{
drawerWidth: 300
});
export default createAppContainer(App);
// HomeScreen.js
import React from 'react';
import {
Image,
Platform,
ScrollView,
StyleSheet,
Text,
TouchableOpacity,
View,
Dimensions,
} from 'react-native';
import { WebBrowser } from 'expo';
import { DrawerNavigator } from 'react-native-navigation';
import { MonoText } from '../components/StyledText';
import { createStackNavigator, createDrawerNavigator, createAppContainer, DrawerActions } from "react-navigation";
import Router from './MenuNavigator';
export default class HomeScreen extends React.Component {
static navigationOptions = {
header: 'Vapeself 2',
};
render() {
const App = createDrawerNavigator({
Home: {
screen: MyHomeScreen,
},
Notifications: {
screen: MyNotificationsScreen,
},
});
const MyApp = createAppContainer(App);
this.props.navigation.dispatch(DrawerActions.openDrawer());
return (
<Router/>
);
}
// LinkScreen.js
import React from 'react';
import { ScrollView, StyleSheet } from 'react-native';
import { ExpoLinksView } from '#expo/samples';
export default class LinksScreen extends React.Component {
static navigationOptions = {
title: 'Links',
};
render() {
return (
<ScrollView style={styles.container}>
{/* Go ahead and delete ExpoLinksView and replace it with your
* content, we just wanted to provide you with some helpful links */}
<ExpoLinksView />
</ScrollView>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: 15,
backgroundColor: '#fff',
},
});
// SettingsScreen.js
import React from 'react';
import { ExpoConfigView } from '#expo/samples';
export default class SettingsScreen extends React.Component {
static navigationOptions = {
title: 'app.json',
};
render() {
/* Go ahead and delete ExpoConfigView and replace it with your
* content, we just wanted to give you a quick view of your config */
return <ExpoConfigView />;
}
}
I don't know what happened because the code doesn't work, and i have this kind of error The component for route 'HomeScreen' must be a React component . But the thing is that its actually work with a TabNavigator. So i really don't understand.
Thank you in advance for the help.

How to debug React Router?

I'm trying to use React Router in my react app which is bounded as wordpress plugin and uses flux to fetch api data.
my entry point looks as it follows
import React from 'react';
import Workshops from './components/workshops';
import Workshop from './components/workshop';
import NotFound from './components/notfound';
import Router, { Route, DefaultRoute, NotFoundRoute, Redirect, Link } from 'react-router';
import json from './config.json';
localStorage.clear();
localStorage.setItem('workshops', JSON.stringify(json));
const AppRoutes = (
<Route path="/" handler={Workshops}>
<DefaultRoute handler={Workshop} />
<Route name="workshop" path=":slug" handler={Workshop}/>
<NotFoundRoute handler={NotFound} />
</Route>
);
Router.run(AppRoutes, Router.HashLocation, (Root) => {
React.render(<Root />, document.getElementById('workshop-booker'));
});
than in my Workshops component I make some links to a given route, I have hash changes but the routed component does not getting fired.
<h3> <Link to="workshop" params={{slug: workshop.slug }}> {workshop.title.rendered }</Link></h3>
You can wrap your Router with a DebugRouter which will print the navigation actions made:
import React, { Component } from 'react';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
import Login from 'components/Login'
import DefaultComponent from 'components/DefaultComponent'
class DebugRouter extends BrowserRouter {
constructor(props){
super(props);
console.log('initial history is: ', JSON.stringify(this.history, null,2))
this.history.listen((location, action)=>{
console.log(
`The current URL is ${location.pathname}${location.search}${location.hash}`
)
console.log(`The last navigation action was ${action}`, JSON.stringify(this.history, null,2));
});
}
}
class App extends Component {
render() {
return (
<DebugRouter>
<Switch>
<Route exact path="/login" name="Login Page" component={Login} />
<Route path="/" name="Home" component={DefaultComponent} />
</Switch>
</DebugRouter>
);
}
}
link to the gist
I made my DebugRouter for functional components
const DebugRouter = ({ children }: { children: any }) => {
const { location } = useHistory()
if (process.env.NODE_ENV === 'development') {
console.log(
`Route: ${location.pathname}${location.search}, State: ${JSON.stringify(location.state)}`,
)
}
return children
}
const Router = () => {
return (
<BrowserRouter>
<Layout>
<Route
render={() => {
return (
<DebugRouter>
<Switch>
<Redirect exact from="/" to={...} />
// <Route/> should be here
<Redirect from="*" to={...} />
</Switch>
</DebugRouter>
)
}}
/>
</Layout>
</BrowserRouter>
)
}
You can try something like this
import React, {Component} from 'react';
import PropTypes from 'prop-types'
import {withRouter} from "react-router-dom";
class RouterDebugger extends Component {
componentWillUpdate(nextProps, nextState){
console.log('componentWillUpdate',nextProps, nextState)
}
componentDidUpdate(prevProps) {
console.log('componentDidUpdate',prevProps)
}
render() {
return null
}
}
export default withRouter(RouterDebugger)
And insert this component in any place you want to debug.
You can pass a prop with some identifier
i hope this help you
You can use the following code to debug React Router:
console.log(this.props.location)
console.log(this.props.match)

Resources