I have an Autocomplete component returned inside the render method of a class. However, it causes nothing to render; taking the component out allows everything else to render as expected.
export default class Home extends Component {
render() {
return (
...
<Row>
<Autocomplete
id="combo-box-demo"
options={[{title: 'Inception'}, {title: 'Dark Knight'}]}
getOptionLabel={option => option.title}
style={{ width: 300 }}
renderInput={params => (
<TextField {...params} label="Combo box" variant="outlined" fullWidth />
)}
/>
</Row>
);
}
}
Taking out Autocomplete and everything inside allows the render to work normally. I am using the example Autocomplete code from Material-UI's guide.
I receive this error in the console:
*Uncaught 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*
What could be causing this render issue? What are the constraints on using Autocomplete(or hooks)?
Your code seems to work correctly.
Could you check the live demo that I have created down below?
Functional component:
https://codesandbox.io/s/material-ui-rh82u?fontsize=14&hidenavigation=1&theme=dark
Class component:
https://codesandbox.io/s/autocomplete-material-ui-tmtoj?fontsize=14&hidenavigation=1&theme=dark
Related
I've got a stateless functional component (see Title below) that uses React-Reveal to display some simple heading elements on render. In addition to having no internal state, Title also doesn't receive any props from its parent component (GameHeader). But for some reason, Title still keeps getting re-rendered whenever I update the overall application state from another, unrelated component elsewhere in the tree and this is causing the React-Reveal animations to run every single time some unrelated app state changes.
// GameHeader.js
import React from 'react';
import Title from './Title';
import Options from './Options';
const GameHeader = () => {
return (
<div>
<Title />
<Options />
</div>
);
}
export default GameHeader;
// Title.js --> this component needs to stop re-rendering so much because it contains entrance animations
import React from 'react';
import { Typography } from '#material-ui/core';
import { useTheme } from '#material-ui/core/styles';
import Zoom from 'react-reveal/Zoom';
import Slide from 'react-reveal/Slide';
import Flip from 'react-reveal/Flip';
const Title = () => {
console.log("Title rendering");
const theme = useTheme();
return (
<>
<Typography variant="subtitle1" color="primary">
<Slide left>Sample</Slide>
</Typography>
<Typography variant="h1" style={{ color: `${theme.palette.indigo.main}` }}>
<Flip delay={800} duration={600} cascade>App</Flip>
</Typography>
<Typography variant="h2" style={{ color: `${theme.palette.orange.dark}` }}>
<Zoom delay={1100} cascade>Title</Zoom>
</Typography>
</>
);
}
export default React.memo(Title);
I've tried wrapping Title in React.memo or converting it to a PureComponent, but to no avail -- it still keeps needlessly re-rendering and re-triggering its animations. I am using hooks + the Context API (w/ useReducer & dispatch) to update my application state elsewhere in the app, but I am not consuming any of that state directly in GameHeader or Title.
I suspect that because React.memo/PureComponent only do a shallow compare between state & props, that maybe there is a phantom prop or something that is non-equivalent between renders that is still getting passed into Title somehow?? But I don't know why that would be, or how to confirm or address that. Or maybe I am just using React.memo incorrectly?
I understand that children re-rendering on parent state changes is just how React works, but I need a way to prevent my transitions from firing after unrelated state changes and React.memo doesn't seem to be doing the trick. Any thoughts?
Tracing it back up the tree got me to the solution. It turns out that the Material UI styled component wrappers I was using around GameHeader were causing GameHeader to remount every time, when I removed the styled component wrappers, GameHeader stopped remounting. Same thing with Title, though in the example I showed above, I had already removed the styled component wrapper from around that one.
These MUI styled component definitions were sitting inside my parent functional components (because they were making use of useTheme), so what I ended up doing was moving those MUI styled component definitions outside of the parent functional components (after the export default statement) and that, for whatever reason, completely resolved the issue.
Thanks #Jayce444 for pointing me in the right direction!
I'm wondering how to make a component like what Ant design did with their message, notification, etc component.
import { message, Button } from 'antd';
const info = () => {
// How to make component / api like this?
message.info('This is a normal message');
};
ReactDOM.render(
<Button type="primary" onClick={info}>
Display normal message
</Button>,
mountNode,
);
Compared to other common library or our own, usually we need to explicitly place the component where we want the component to show.
Other framework
ReactDOM.render(
<div>
<Button type="primary" onClick={showMessage}>
Display normal message
</Button>
{/* Others need to do this */}
<Message active={messageStatus} content="Lorem ipsum" />
</div>,
mountNode
);
I checked their github, but I can't understand the code since they are using typescript and a lot of abstraction.
Also tried using React.createElement() method, but still couldn't figured out how to put the created element to the dom tree.
I am using SubMenu in another Component as I require State for checkboxes inside Menu. I get this warning when I am passing a method as props to that custom Component I made.
This is the whole warning:
Invalid values for props additem, selectallzones on li tag.
Either remove them from the element, or pass a string or number value
to keep them in the DOM. For details, see
(link)
My parent Component looks like this, keep in mind addItem() and selectAllZones() are in this component (I have simplified the code a bit so it only has things that are in question):
<SubMenu key="City" title="City">
{this.state.cities.map(city => <SubCity key={city.city} city={city} additem={this.addItem} selectallzones={this.selectAllZones}></SubCity>)}
</SubMenu>
And my SubCity Component looks like this:
<SubMenu {...this.props} key={this.props.city.city} title={this.props.city.city}>
{this.props.city.zone.map(zone =>
<Menu.Item key={zone.id}><Checkbox disabled={this.state.checkedAll} onChange={(e) => this.props.additem('zones', zone.zone, e)}>{`Zone ${zone.zone}`}</Checkbox></Menu.Item>)}
</SubMenu>
I added the {...this.props} in SubMenu component of SubCity looking at another StackOverflow question for other errors I was getting, and I assume this is what is causing the problem. But I can't remove that or my code doesn't run at all. Is there any way I can do this without any warnings in the console? (The code does work, only get a warning in the console.)
I want to render in react-native project. But simulator shows me the error:
Invariant Violation: View config not found for name div
What is the matter?
Is there a solution for rendering <div> in react-native?
Code sample:
render() {
return (
<div>123</div>
);
}
<div> is an invalid React Native Component
You should use React Native Basic Components
import { View, Text } from 'react-native';
render() {
return (
<View>
<Text>123</Text>
</View>
);
}
View is a container that supports layout with flexbox, style, some touch handling, and access controls. Whereas <Text> can be used in order to display any text.
the React Native documentation does not list HTML elements as valid view components. There is no view config for <div> because <div> is not a React Native component.
I use material-ui components in react with react-router. I have a problem when I want to display list-items that are supposed to work as link elements, but also contain a submenu inside that should not trigger the parent link. It does and I don't know how to disable it.
var iconMenu =
<IconMenu iconButtonElement={<IconButton><MoreVertIcon /></IconButton>}>
<MenuItem primaryText='change name' onTouchTap={this.edit}/>
<MenuItem primaryText='delete' onTouchTap={this.delete} />
</IconMenu>
<ListItem
key={i}
containerElement={<Link to={`/items/${item.id}`} />}
rightIconButton={iconMenu}
/>
When I click the iconMenu button, I do not want the <Link to={`/items/${item.id}`} /> to be triggered, so that I stay in the page. But it does. So how can I fix this problem? I tried to add event handler to run stopPropagation() but it was not successful...
Thanks!
For React Router v4, add
onTouchTap={() => this.props.history.push(`/items/${item.id}`)}
to the ListItem, instead of containerElement.
Use import { withRouter } from 'react-router-dom' and export default withRouter(Foo) to add history to the component's props.
First of all, I'd like to admit that I do not like material-ui and thus do not recommend it to people who consider starting a project with it. The reasoning behind is that you sacrifice too much time customising the components to your needs - a solution that is opposite to the idea of React. It also uses inline styles that you always have to overwrite in the component file, not in your scss or less. This sucks big time. I don't even mention all the UI interaction actions that are handled with JS that could make your performance ache.
Another short mention is to the react-router. Unfortunately I'm not a fan of it either. Guys, why do you change the API in every next release? Why is it so damn difficult to just reset the location queries? Just look at FlowRouter and see how fantastic a route API should be implemented.
Anyways, my solution was to implement a wrapper around the <Link /> component and move the <IconMenu /> outside of the <Link /> wrapper:
<li key={i}>
<ListItem
key={i}
containerElement={<Link to={`/items/${item.id}`} />}
/>
{iconMenu}
</li>