How to make GridList face vertically in One Row with React and materialUI on Mobile - node.js

How do I make Materia-UI GridList Face vertically in One Row on Mobile?
My GridList is two in a row which is what I wanted but when I inspect it on mobile it still shows two in a row instead of One. that means it's not responsive, How do I make it responsive?
this is my Events Component.
import React from "react";
import { Link } from "react-router-dom";
import axios from "axios";
import GridList from "#material-ui/core/GridList";
import GridListTile from "#material-ui/core/GridListTile";
import GridListTileBar from "#material-ui/core/GridListTileBar";
import ListSubheader from "#material-ui/core/ListSubheader";
mport IconButton from "#material-ui/core/IconButton";
import Button from "#material-ui/core/Button";
import { withStyles } from "#material-ui/core/styles";
import Typography from "#material-ui/core/Typography";
const useStyles = (theme) => ({
root: {
display: "flex",
flexWrap: "wrap",
justifyContent: "space-around",
overflow: "hidden",
backgroundColor: theme.palette.background.paper,
},
gridList: {
width: 1000,
height: 950,
},
icon: {
color: "rgba(255, 255, 255, 0.54)",
},
});
class EventsList extends React.Component {
constructor(props) {
super(props);
this.state = { events: [] };
}
componentDidMount() {
axios
.get("http://localhost:9000/events/")
.then((response) => {
this.setState({ events: response.data });
})
.catch(function (error) {
console.log(error);
});
}
render() {
const { classes } = this.props;
return (
<div className={classes.root}>
<GridList cellHeight={330} className={classes.gridList} spacing={8}>
<GridListTile key="Subheader" cols={2} style={{ height: "auto" }}>
<ListSubheader component="div">December</ListSubheader>
</GridListTile>
{this.state.events.map((tile) => (
<GridListTile key={tile.eventImage}>
<img src={tile.eventImage} alt={tile.title} />
<GridListTileBar title={tile.title} titlePosition="top" />
<GridListTileBar
paragraph={tile.description}
actionIcon={
<IconButton
aria-label={`info about ${tile.title}`}
className={classes.icon}
></IconButton>
}
/>
</GridListTile>
))}
</GridList>
</div>
);
}
}
export default withStyles(useStyles)(EventsList);
this is the List of my events displayed by GridList on Mobile
but something like this is what I want to see when I am on Mobile.

Since you are using class based component, you can use withWidth to conditionally set cols value to GridList.
See working example here in codesandbox
Example code snippet
class TitlebarGridList extends Component {
render() {
const { classes, width } = this.props; // <---- see here
let columns = width === "xs" || width === "sm" ? 1 : 2;
console.log("=========>", width);
return (
<div className={classes.root}>
<GridList cellHeight={200} className={classes.gridList} cols={columns}> {/* //<---- see here */}
<GridListTile key="Subheader" cols={3} style={{ height: "auto" }}>
<ListSubheader component="div">December</ListSubheader>
</GridListTile>
{tileData.map(tile => (
<GridListTile key={tile.title}>
<img className={classes.image} src={tile.img} alt={tile.title} />
</GridListTile>
))}
</GridList>
</div>
);
}
}
TitlebarGridList.propTypes = {
classes: PropTypes.object.isRequired
};
export default compose(
withStyles(styles, {
name: "TitlebarGridList"
}),
withWidth() //<---- see here
)(TitlebarGridList);
Note: withWidth will be deprecated sometime in the future, so consider to use useMediaQuery hook (in that case you have to switch to functional component).

Related

Datepicker clicking month error: Attempt to invoke interface method 'int com.facebook.react.bridge.readablearray.size()' on a null object reference

Everything is ok but when clicking month then got the error: Attempt to invoke interface method 'int com.facebook.react.bridge.readablearray.size()' on a null object reference.
This is the Call page:
import React from 'react';
import { SafeAreaView, View, StatusBar, Alert } from 'react-native';
import {
Layout,
Icon, Divider, Text,
TopNavigation, TopNavigationAction,
Datepicker } from '#ui-kitten/components';
const MenuIcon = (props) => (
<Icon {...props} name='menu' style={{width: 36, height: 36, color: 'gray', alignItems: 'center'}}/>
);
export const PatrolScreen = ({ navigation }) => {
const [date, setDate] = React.useState(new Date());
const MenuAction = () => (
<TopNavigationAction icon={MenuIcon} onPress={navigation.toggleDrawer}/>
);
return (
<Layout style={{ flex: 1 }}>
<StatusBar hidden={false} />
<TopNavigation title='Patrol' alignment='center' accessoryLeft={MenuAction}/>
<Divider/>
<Layout style={{ flex: 1}}>
<Datepicker
date={date}
onSelect={nextDate => setDate(nextDate)}
/>
</Layout>
</Layout>
);
};
The following is my App.js:
import React from 'react';
import * as eva from '#eva-design/eva';
import { ApplicationProvider, IconRegistry } from '#ui-kitten/components';
import { IoniconsPack } from './utils/ion-icons';
import { MaterialCommunityIconsPack } from './utils/materialcommunity-icons';
import { AppNavigator } from './routes/navigation';
import { ThemeContext } from './utils/theme.context';
export default () => {
const [theme, setTheme] = React.useState('dark');
const toggleTheme = () => {
const nextTheme = theme === 'light' ? 'dark' : 'light';
setTheme(nextTheme);
};
return (
<>
<IconRegistry icons={[IoniconsPack, MaterialCommunityIconsPack]} />
<ThemeContext.Provider value={{ theme, toggleTheme }}>
<ApplicationProvider {...eva} theme={eva[theme]}>
<AppNavigator />
</ApplicationProvider>
</ThemeContext.Provider>
</>
);
};
How to resolve this? Thanks.

Data only shows up when I click twice on submit on ReactJs

I'm trying to create a link shortener using Reactjs, after I set up the post request for the long URL, I need to display the resulting short URL. The problem is I can't seem to be able to do that. The resulting link only shows up when I click twice on the submit button, but if I refresh the page and click submit, the shortened link does not show up.
I'm hoping you can help me with that, here's my code:
import './App.css';
import Button from '#mui/material/Button';
import TextField from '#mui/material/TextField';
import React, {Component} from 'react';
import axios from 'axios'
class App extends Component {
constructor(){
super()
this.changelongUrl=this.changelongUrl.bind(this)
this.onSubmit=this.onSubmit.bind(this)
this.state={
longUrl:'',
shortenedUrl :[],
urls:[]
}
}
changelongUrl(event){
this.setState({
longUrl : event.target.value
})
}
onSubmit(event){
event.preventDefault()
const registered={
longUrl: this.state.longUrl
}
axios.post('http://localhost:5000/api/url/shorten',registered)
axios.get('http://localhost:5000/')
.then(response => {
this.setState({ urls: response.data });
console.log(this.state.urls)
})
this.setState({
shortenedUrl: this.state.urls.filter(url => url.longUrl === this.state.longUrl).map(filteredUrl => (
filteredUrl.shortUrl
))
})
console.log(this.state.shortenedUrl)
this.setState({
longUrl:''
})
}
render(){
return(
<div className="App">
<header className="App-header">
<form onSubmit={this.onSubmit} style={{
display: 'flex',
flexDirection: 'column'}}>
<TextField value={this.state.longUrl} onChange={this.changelongUrl}
style={{ marginBottom: 22 }} className="textfield" id="outlined-basic"
label="Please Input Your Link" variant="outlined" />
<Button style={{
marginBottom: 22,
backgroundColor: "#47597E",
padding: "10px 20px",
fontSize: "18px"}}
variant="contained" type= 'Submit'>Shorten</Button>
</form>
<a href={this.state.shortenedUrl}>{this.state.shortenedUrl}</a>
</header>
</div>)
}
}
export default App;

React navigation throwing error when moving between screens

I have defined two screens in my App.js.
import 'react-native-gesture-handler';
import * as React from 'react';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
import HomeScreen from './HomeScreen';
import FAQScreen from './FAQScreen';
const Stack = createStackNavigator();
function App() {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="HomeScreen">
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="FAQ" component={FAQScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
export default App;
In my HomeScreen.js I want to simply press a button and navigate to FAQScreen.
However, I keep getting an error:
The action 'NAVIGATE' with payload {"name":FAQScreen}" was not handled by any navigator.
Do you have a screen named 'FAQScreen'?
I tried to do multiple Google search and found no solution to solve this.
Here is my HomeScreen.js for completeness.
mport 'react-native-gesture-handler';
import React, { Component } from 'react';
import { StyleSheet, Text, SafeAreaView, View, Button} from 'react-native';
class MyButtonText extends Component {
render() {
var phoneHeight = 500;
const myFontSize = phoneHeight/25;
return (
<Text style={{ fontFamily: "Courier New", fontSize: myFontSize }} onPress = {() => console.log("text clicked")}>
{this.props.children}
</Text>
);
}
}
class MyInfoText extends Component {
render() {
var phoneHeight = 500;
const myFontSize = phoneHeight/30;
return (
<Text numberOfLines = {2} style={{ fontFamily: "Courier New", fontSize: myFontSize, alignItems: "center", textAlign: "center"}}>
{this.props.children}
</Text>
);
}
}
function HomeScreen({ navigation }) {
const toolKaiserID = "alkjakljf";
navigateToScreen=()=>{
console.log('Going to FAQ screen now...');
navigation.navigate('FAQScreen')
}
return (
// this is a comment
<SafeAreaView style={styles.container}>
{/* top bar */}
<View style = {topBarStyle.container}>
<Button onPress={this.navigateToScreen} title="Information" />
<MyButtonText>ID: {toolKaiserID}</MyButtonText>
<Button title="Feedback"/>
</View>
{/* info bar */}
<View style = {infoBarStyle.container}>
<MyInfoText>paper on floor -- tool(s) on top; take photos from at least 3ft/1m away</MyInfoText>
</View>
{/* camera view */}
<View style = {cameraStyle.container}></View>
{/* bottom bar */}
<View style = {bottomBarStyle.container}>
<Button title="1 Photos"/>
<Button title="2 Check"/>
<Button title="3 Editor"/>
<Button title="4 Paper"/>
</View>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#434343',
},
});
const viewStyle = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'blue',
},
});
const topBarStyle = StyleSheet.create({
container: {
flex: 1,
flexDirection: "row",
justifyContent: 'space-around',
backgroundColor: 'blue',
},
});
const infoBarStyle = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'white',
},
});
const cameraStyle = StyleSheet.create({
container: {
flex: 5,
backgroundColor: 'red',
},
});
const bottomBarStyle = StyleSheet.create({
container: {
flex: 1,
flexDirection: "row",
justifyContent: 'space-around',
backgroundColor: 'yellow',
},
});
export default HomeScreen;
There is no FAQScreen name in your stack navigator
<Stack.Screen name="FAQ" component={FAQScreen} />
When you use navigate, it's need the name, that is "FAQ"
If you want to navigate using name "FAQScreen", you can set like this:
<Stack.Screen name="FAQScreen" component={FAQScreen} />

How to use Material Ui on React. getting error Invalid Hook call

`×
Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
You might have mismatching versions of React and the renderer (such as React DOM)
You might be breaking the Rules of Hooks
You might have more than one copy of React in the same app`
I am new to React, my code was working fine but I decided to use MaterialUi today, now it's giving me errors, I have tried googling but I didn't succeed. Another thing is that my this.state.events is returning an Empty array, instead of a list of events. How do I fix this?
My React-dom version is ─ react-dom#16.13.1 and React version is ─ react#16.13.1
import React, { Component } from "react";
import { Link } from "react-router-dom";
import axios from "axios";
import { makeStyles } from "#material-ui/core/styles";
import GridList from "#material-ui/core/GridList";
import GridListTile from "#material-ui/core/GridListTile";
import GridListTileBar from "#material-ui/core/GridListTileBar";
import ListSubheader from "#material-ui/core/ListSubheader";
import IconButton from "#material-ui/core/IconButton";
export default class EventsList extends Component {
constructor(props) {
super(props);
this.state = { events: [] };
}
componentDidMount() {
axios
.get("http://localhost:9000/events/")
.then((response) => {
this.setState({ events: response.data });
})
.catch(function (error) {
console.log(error);
});
}
render() {
const useStyles = makeStyles((theme) => ({
root: {
display: "flex",
flexWrap: "wrap",
justifyContent: "space-around",
overflow: "hidden",
backgroundColor: theme.palette.background.paper,
},
gridList: {
width: 500,
height: 450,
},
icon: {
color: "rgba(255, 255, 255, 0.54)",
},
}));
const classes = useStyles();
return (
<div className={classes.root}>
<GridList cellHeight={180} className={classes.gridList}>
<GridListTile key="Subheader" cols={2} style={{ height: "auto" }}>
<ListSubheader component="div">December</ListSubheader>
</GridListTile>
{this.state.events.map((tile) => (
<GridListTile key={tile.img}>
<img src={tile.img} alt={tile.title} />
<GridListTileBar
title={tile.title}
subtitle={<span>by: {tile.author}</span>}
actionIcon={
<IconButton
aria-label={`info about ${tile.title}`}
className={classes.icon}
></IconButton>
}
/>
</GridListTile>
))}
</GridList>
</div>
);
}
}
makeStyles returns a hook i.e. useStyles. You can only use hooks in functional components.
One option is to convert your class component to functional. Also make sure to put makeStyles code outside of component(you don't want to execute it on every re-render)
import React, { useEffect, useState } from "react";
// other imports
const useStyles = makeStyles((theme) => ({
root: {
display: "flex",
flexWrap: "wrap",
justifyContent: "space-around",
overflow: "hidden",
backgroundColor: theme.palette.background.paper,
},
gridList: {
width: 500,
height: 450,
},
icon: {
color: "rgba(255, 255, 255, 0.54)",
},
}));
const EventsList = () => {
const [events, setEvents] = useState([]);
const classes = useStyles();
useEffect(() => {
axios
.get("http://localhost:9000/events/")
.then((response) => {
this.setState({ events: response.data });
})
.catch(function (error) {
console.log(error);
});
}, []);
return (
<div className={classes.root}>
// rest of code...
</div>
);
};
Another option is to keep class based component intact and use withStyles.
See withStyles API doc:
Use the function signature if you need to have access to the theme. It's provided as the first argument.
import { withStyles } from "#material-ui/core";
const styles = (theme) => ({
root: {
display: "flex",
flexWrap: "wrap",
justifyContent: "space-around",
overflow: "hidden",
backgroundColor: theme.palette.background.paper,
},
gridList: {
width: 500,
height: 450,
},
icon: {
color: "rgba(255, 255, 255, 0.54)",
},
});
class EventsList extends Component {
constructor(props) {
super(props);
this.state = { events: [] };
}
componentDidMount() {
axios
.get("http://localhost:9000/events/")
.then((response) => {
this.setState({ events: response.data });
})
.catch(function (error) {
console.log(error);
});
}
render() {
return (
<div className={classes.root}>
<GridList cellHeight={180} className={classes.gridList}>
<GridListTile key="Subheader" cols={2} style={{ height: "auto" }}>
<ListSubheader component="div">December</ListSubheader>
</GridListTile>
{this.state.events.map((tile) => (
<GridListTile key={tile.img}>
<img src={tile.img} alt={tile.title} />
<GridListTileBar
title={tile.title}
subtitle={<span>by: {tile.author}</span>}
actionIcon={
<IconButton
aria-label={`info about ${tile.title}`}
className={classes.icon}
></IconButton>
}
/>
</GridListTile>
))}
</GridList>
</div>
);
}
}
export default withStyles(styles)(EventsList);
Well, it is pretty much what the error says. Hooks can be used only with functional components. EventsList is a class component and you are trying to use makeStyles in it.
I faced the same issue, but I noticed that terminal was showing a "compiled successfully" message, and still the browser gave me this error.
I actually installed the material-ui/icons as: sudo npm install -g #material-ui/icons
( I thought I'll install it globally as an administrator so I will not have to install material-ui, every time on different projects/react apps)
Inside the react app I was working, I just ran ( npm install #material-ui/icons ) which updated the node_modules folder inside my react app, and the error was gone and everything was working fine on the browser as well.
Solution: just run "npm install #material-ui/core" and "npm install #material-ui/icons" on the terminal, being in the react app directory your'e working in. Hopefully, everything will get fixed.

How can I modify this code so that render waits for Promise Items?

I am new to React and I load all the data from my database initially on page load but there is info I need to find in an array and apparently it isn't instant. What do I need to do to make sure the render method only renders the objects when the object promises have resolved?
I haven't tried much... I'm really stuck here.
This seems different than the other problems I've read here because I load a bunch on info in the beginning just fine but I need to call some team information every time a function is called so it isn't as simple as loading it once because the object i need is always different.
This code is the main issue. I also included the full file below:
I did some modification to the code in a edit: I realized that I just need to call the opponent team because I have the player team already.
if (team.id === game.team_1) {
var redTeam = team;
// set blueTeam based on game.team_1
// firebase.teams().doc('teams/{game.team_2}')
} else {
var blueTeam = team;
// set redTeam based on game.team_1
// firebase.teams().doc('teams/{game.team_1}')
}
Full file:
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import Async from 'react-promise'
import { withFirebase } from '../Firebase';
// import * as ROUTES from '../../constants/routes';
import { Container, Image, Spinner, Col, Row, Card, Accordion, Button } from 'react-bootstrap'
class PlayerGameList extends Component {
constructor(props) {
super(props);
this.state = {
loadingTeams: false,
loadingSchedule: false,
teams: [],
schedule: []
};
}
componentDidMount() {
this.setState({
loadingTeams: true,
loadingSchedule: true,
});
this.unsubscribe = this.props.firebase
.teams()
.where('players', 'array-contains', '-LXkkB7GNvYrU4UkUMle')
.onSnapshot(snapshot => {
let teams = [];
snapshot.forEach(doc =>
teams.push({ ...doc.data(), uid: doc.id }),
);
this.setState({
teams,
loadingTeams: false,
});
});
this.unsubscribe2 = this.props.firebase
.schedule()
.onSnapshot(snap => {
let schedule = [];
snap.forEach(doc =>
schedule.push({ ...doc.data(), uid: doc.id }),
);
this.setState({
schedule,
loadingSchedule: false,
});
});
}
componentWillUnmount() {
this.unsubscribe();
this.unsubscribe2();
}
render() {
const { teams, schedule, loadingTeams, loadingSchedule } = this.state;
return (
<div>
<h2>Games</h2>
{loadingTeams && loadingSchedule && <div colSpan="12"><Spinner animation="border" role="status">
<span className="sr-only">Loading...</span>
</Spinner></div>}
{/* CONTENT */}
<Container fluid>
<Row>
{getTeams({ teams, schedule })}
</Row>
</Container>
</div >
);
}
}
function getTeams({ teams, schedule }) {
if (!teams) {
return null;
}
if (!teams.length) {
return null;
} else {
return teams.map(team => getGames({ team, schedule }))
}
}
function getGames({ team, schedule }) {
schedule.sort((a, b) => (a.time > b.time) ? -1 : 1)
if (!schedule) {
return null;
}
if (!schedule.length) {
return null;
} else {
return schedule.map(game => guts({ team, game }));
}
}
function guts({ team, game }) {
const image = {
height: '25px',
width: '25px'
}
if (team.id === game.team_1) {
var redTeam = team;
// set blueTeam based on game.team_1
// firebase.teams().doc('teams/{game.team_2}')
} else {
var blueTeam = team;
// set redTeam based on game.team_1
// firebase.teams().doc('teams/{game.team_1}')
}
if (game.team_1 === team.id || game.team_2 === team.id) {
var time = new Date(game.time.seconds * 1000);
var dateFormat = require('dateformat');
var finalTime = dateFormat(time, 'ddd mmm dd, h:MM tt')
return (
<Col lg='4' md='6' sm='12' key={game.uid} style={{ marginBottom: '15px' }}>
<Card>
<Card.Body>
<Row>
<Image src={team.logo} style={image} roundedCircle />
<p>{team.name}</p>
<div style={{ height: '25px', width: '25px', backgroundColor: 'red' }}></div>
</Row>
<Row>
<Image src={team.logo} style={image} roundedCircle />
<p>{team.name}</p>
<div style={{ height: '25px', width: '25px', backgroundColor: 'blue' }}></div>
</Row>
<Row>
<div>
{finalTime}
</div>
</Row>
</Card.Body>
<Accordion>
<Card style={{ margin: '0', padding: '0' }}>
<Card.Header>
<Accordion.Toggle as={Button} variant="link" eventKey="0">
Show Match IDs
</Accordion.Toggle>
</Card.Header>
<Accordion.Collapse eventKey="0">
<Card.Body>{game.match_id}</Card.Body>
</Accordion.Collapse>
</Card>
</Accordion>
</Card>
</Col>
);
}
}
export default withFirebase(PlayerGameList);
The items all load blank then a few seconds later all the console logs come through with the array objects. When I tell it to await the program just throws an error.

Resources