I'm pretty new to ReactJS, but I'm slowly getting behind it.
I want to create a smart component, it should detect if it is "inside" another component and render differently then.
Example:
<Menu>
<Item />
</Menu>
Here, the item component should render as an anchor.
If used inside any other component or a div, it should simply render as a div as well.
Is there an easy way to check, if a component is inside another component in React?
You could solve this by passing a prop, saying something about the context the component is being used in.
The simplest solution in your case would be to, whenever you use the item component in menu, you pass a prop.
render(){
<Menu>
<Item insideMenu={true} />
</Menu>
}
Then inside the render you have two different return statements (depending on the insideMenu-prop).
// Item.jsx
render() {
if(this.props.insideMenu)
return (whatever)
return (whateverElse)
}
Normally I wouldn't reccomend this though. Components, in my opinion, should be reuseable and generic if possible. In this case, I'd argue it would be better to have two components: Item and MenuItem. So then it would be
<Menu>
<MenuItem>
</Menu>
<AnythingElse>
<Item>
</AnythingElse>
Inside MenuItem, you may very well use the Item component as well, if they share the same behaviour. So in that case, MenuItem would render Item, as well as the extra behaviour required for the menu. Or simply wrap it inside an anchor-tag, if that's all there is to it.
Either solution works, but the latter is (in my opinion) cleaner. Less surprises, easier to read, and less that can go wrong (no need to juggle props).
Related
Code example: https://codesandbox.io/s/jovial-paper-s0c69?file=/src/App.js
Material UI makes smooth collapse.
But, when I put JSX to external component, smooth brakes.
I made code example with smooth collapse and without smooth collapse.
How can I keep Lists in external component and keep smooth collapse?
But, when I put JSX to external component
Your example does not actually use an external component, you define Lists inside of NestedList and that function is consequently recreated on every render.
The desired behavior can be achieved by actually having a separate Lists component that receives the required props from its parent:
<Lists open={open} handleClick={handleClick} />
I was trying to change URL path by clicking the <Tab/> component, I searched it through the Material-UI Tab API but couldn't find anything. Then I came across with the solution as
<Tab label='Most popular ideas' to='/myPath' component={Link} />
The question is how can you use component property even if it's not one of the <Tab/>'s props and how it's working?
Take a look at the documentation:
Any other properties supplied will be provided to the root element
(ButtonBase).
Here's the API props for ButtonBase:
https://v4-0-2.material-ui.com/api/button-base/
Props you'll provide to the Tab element which not being used by the element will bubble down to the next component, which is in this case ButtonBase that uses your component prop.
It looks like antd (https://ant.design) is generating an alarming amount of nesting to achieve its purpose. Maybe I'm wrong, but I feel there must be a better way.
For instance, I added colored text, like so:
<Text type="danger">Some words</Text>
At the DOM, it looks as expected:
<span class="ant-typography ant-typography-danger">Some words</span>
But when inspecting with react-tools, it looks bloated and doubled:
("...>" = omitted attributes)
<Text type="danger">
<withConfigConsumer(Base) ...>
<Context.consumer>
<Base ...>
<LocalReceiver ...>
<ReactResizeObserver ...>
<Typography ...>
<Content.consumer>
<span ...>
"Some words"
...
</Text>
<Context.consumer>
<Base ...>
<LocalReceiver ...>
<ReactResizeObserver ...>
<Typography ...>
<Content.consumer>
<span ...>
"Some words"
...
</Context.consumer>
Admittedly, I don't have enough experience with React. But isn't this excessive? Why is it doubled? And most of all: how can I use antd and avoid this?
You can't avoid this when using antd as this is a React design pattern their team decided to use. Those wrapper components are HOCs - higher-order components and their purpose is to apply/reuse some logic on their child components.
For example, in their GitHub repo, you can clearly see that Text, Title and Paragraph are simply the same Typography component whose inner text gets styled differently depending on if its passed a Text, Title or a Paragraph prop. This is to ensure extensibility: if they decide to create a Quote component, they will simply add a Quote entry to the Typography component, and define Quote styling that would possibly include italic text. The wrapper Typography component would then pass down this new italicized style to its child component - the inner text.
As for ReactResizeObserver, many Ant Design components require to have some kind of onResize event listener attached to themselves in order to be responsive - to change their size or structure based on the screen width. Instead of defining the same onResize listener and handler on every component that needs this functionality, they have created a single HOC that can wrap any component under the hood and allow it to be responsive.
You really shouldn't care about this, as this is common practice with many popular libraries like React Router or Redux.
I wanted to get an understanding on what people would consider best practice for layout of their react components, and if the layout styling should or should not be tightly coupled within the component itself.
Say I have a custom component that will be reused many times within the application, there may be times when I was them to be stacked Vertically down the page, with margin-bottom:20px;, whereas there may be cases I would like them spread out horizontally across the page with margin-right:20px;
It doesn't feel right if I were to have margins, or other layout attributes tightly coupled with the component? I would have thought that I should be able to render by component in isolation, without it having positional styling coupled along with it?
If you're using the component multiple times in one layout then of course the margin is not part of your component but the component that contains it.
You can use different methods to achieve your desired margin, for instance you have the css grid gap that defines just that.
However if you are using flex, you might have to pass the desired margin down to the component. So having something like this inside the component would be helpful in that case:
<div id="container" style={[styles.container, this.props.margin]}>
That way you can give it a default margin in the container style while still allowing yourself to pass a dynamic value through props when using in different places.
You could have a prop that defines the type of the component, let's say, a type prop. And you can apply the classes based on the type prop you receive with a default type.
static propTypes = { type: PropTypes.oneOf(['info', 'warning', 'error']) };
default propTypes = { type: 'info' };
and the render would look like this :
<div className={styles[this.props.type]}>content</div>
Or you can just have a single way your component look and add a className prop and/or just pass your custom styles as inline styles.
<MyComponent style={{ marginBottom: '30px' }} className="CustomStyleInClass" type="error" />
You could either use one, two or all. It depends on the component and the flexibility you need.
I'm trying to implement a pop over that can show on any screen in the web application, using React+Redux+React router
The popover is a container, that is triggered by the application state.
But how is the best practice to do such a thing, since the background is transparent, and it should just show on any screen that is currently presented.
Should it be on top of the router, on hidden, and unhide on present? I can seem to find any example for this senario...
Popover can sit inside Root component, something like this.
<App>
<HomePage />
{shouldShowPopOver && <PopOver />}
</App>
You can dispatch { type: TOGGLE_POPOVER } action anywhere, to alter shouldShowPopOver. The styling(transparent, whole page etc) should be done through css.
You ca use react-bootstrap popover. Checkout the link
https://react-bootstrap.github.io/components.html#popovers
I'm using react-modal component and it works pretty well.
I have used react-modal-dialog before and it works like a charm! The benefit of this library is that you can define your <Modal> component near where the source of trigger is (some button?) and it is easy to trace the condition that determines whether the modal is displayed since it is near the trigger source.
Using this library, technically it does not matter where you put the modal component among your markup as the CSS of the modal makes it appear above all other elements.