is there a way to have templates in react - reactjs

I have built an element which is kind of template. (e.g, thumbnail container with image at the top and something in the footer with dynamic content between them)
the dynamic content can be different types of DOM elements, based on the state.
I did it with adding logic in the render method which "injects" the dynamic part.
Does this make sense (having logic in the render method which returns different react components)?
Is there a better way for templating? (i'm not looking for projects that add this capability, wanted to know if there's a "react way" to do so.
Thanks!
edit: here's the code I was referring to (coffeescript):
internalContent: ->
switch #props.title
when "title1" then SomeReactFactory(props)
when "title2" then SomeOtherReactFactory(props)
render ->
...
DOM.div
className: 'panel'
#internalContent()
the internalContent() method is dynamically adding some React Component based on the prop

This is the React way.. And you should make use of it to target your specific domain.
For example a Button in React could be written like this:
const MyButton = ({ text, type = "normal", color = "blue", onClick }) => {
return (
<button
onClick={onClick}
style={{backgroundColor: color }}
className={"my-button my-button--type" + type}>
{text}
</button>);
};
Or a layout component:
const MyLayout = ({side, nav, main}) => {
return (
<div className="container">
<nav>{nave}</nav>
<aside>{side}</aside>
<div className="main">{main}</div>
</div>
)
}
Now you can composite it for example like this:
class App extends Component {
...
render() {
<MyLayout
nav={<MyNav/>}
side={<MySideBar items={...} />}
main={<MyButton onClick={this.onClick} text="Main Button"}
/>
}
}
Dont try to pack everything in a big Component which will do everything, the trick in React is to make small reusable Components and composite them.
You could also create a bunch of components which you can use across many projects.

Related

React Native Components Override styles "leaking"

I'm trying to build my own component library specific to my React Native app using the Atomic Design Methodology, so I have small components like Paragraph, Title, Wrap, Button, Subtitle etc. in a single file called "Atoms". I can import them in my other components like so:
import { Paragraph, Title, Wrap, Button, Subtitle } from "../Atoms";
I'm building them using tailwind-react-native-classnames. It's a great package using Tailwind CSS with lots of useful features like platform prefixes and dark mode support.
Now, sometimes I need unique style changes on these components, so I have a style prop to mix the style Object to one, it works like this:
<Subtitle style={tw`pt-20`}>Some Text</Subtitle>
And in the component:
const Subtitle = ({ style, children }) => (
<Text style={Object.assign(tw`text-xl mb-3 text-octonary dark:text-white`, style)}>
{children}
</Text>
);
This works well, any style can be overwritten, it's intuitive to work with and gives me lots of freedom. But here's the problem, the changes (inconsistently, and not every component) seems to effect the same components on other Screens. So in the above example the tw`pt-20` translates to paddingTop: 5rem and applies it to other places, other Screens, with the same component, that shouldn't even have this style applied to it.
Why is this happening? Is it cashed somehow? And how can I fix it?
Thanks in advance for any help/suggestions.
I found a solution, thanks to #Abe I experimented using tw.style(). So instead of this:
const Subtitle = ({ style, children }) => (
<Text
style={Object.assign(tw`text-xl mb-3 text-octonary dark:text-white`, style)}
>
{children}
</Text>
);
I did this:
const Subtitle = ({ style, children }) => (
<Text
style={tw.style(
"text-xl",
"mb-3",
"text-octonary",
"dark:text-white",
style
)}
>
{children}
</Text>
);
It's not as close to normal Tailwind CSS since every class needs separate quotes and also be separated by commas, but it works! But then I went even further and did this:
const Subtitle = ({ style, children }) => {
const s = tw`text-xl mb-3 text-octonary dark:text-white`;
return <Text style={tw.style(s, style)}>{children}</Text>;
};
It's more compact, I can code vanilla tailwind and no "leaking". So win-win-win!

How to build react component can change view type

I'm working a reactjs project have require to build a component can change view type. Like: the component have "view as icon" and "view as list", and have a button to switching eachother. Which the best way to archive that. Thanks
Edit: Sorry for making confuse
This is exactly what i want. As you can see, i have a mediaComponent and i want it can display in 2 different way: as a list and as thumbnail. So how can i do that with react. I don't actually have code for that.
p/s: I have tried conditional rendering but because it's different in render it's require to re-render the component with forceUpdate(). That's don't really look nice. So i hove there are another solution for that.
Render as thumbnail
Render as list
Something like that perhaps:
class MyComponent extends React.Component {
state = {
isList: false
}
toggleList = () => this.setState({ isList: !this.state.isList})
render(){
const { isList } = this.state;
return (
<div>
{isList ? <ListComponent /> : <GridComponent />}
<button onClick={this.toggleList}>Toggle</button>
</div>
)
}
}
export default MyComponent;

How to pass padding/margin as props in React-Bootstrap components

I am trying to apply margins and paddings with React-Bootstrap as props.
I passed the docs through but haven't found any mention adding padding or margin in there as it is in official bootstrap docs (3th and 4th). I know it doesn't support well Bootstrap 4, so tried with both.
I tried to pass params as p={1}, paddingxs={5} or mt='1' but it doesn't recognize any of them. More over tried to find any Spacing element in React-Bootstrap folder, but failed.
Paddings and margins work as classnames. But I feel there must be a way to it without Bootstrap classes. There must be a kind of property.
First include bootstrap CSS in your src/index.js or App.js
import 'bootstrap/dist/css/bootstrap.min.css';
Then you can style your component by passing desired bootstrap CSS class name as className prop in React, for example:
import React from "react"
import Container from "react-bootstrap/Container";
function MyComponent() {
return (
<Container fluid className="p-0">
<SomeOtherComponent />
</Container>
);
}
export default MyComponent
Above code will add p-0 CSS class to Container.
Reference
React - How do I add CSS classes to components?
React-Bootstrap - Stylesheets
You can add margin and padding by using default React's style:
const divStyle = {
marginLeft: '10px',
};
function HelloWorldComponent() {
return <div style={divStyle}>Hello World!</div>;
}
Refrenced from here
The answer is: there is no props from React Bootstrap to use margins/paddings.
You can use props for col class, but no for margins.
Example:
<Col className="col-6 col-md-3 mb-3 pt-2">
// there you have a Col component from React-Bootstrap 4
// it has some grid system classes, that you can use as props like this:
https://react-bootstrap.github.io/layout/grid/
<Col xs={6} md={3} className="mb-3 pt-2">
// but as you can see, the native classes of Bootstrap 4 like
// mt, mb, pt, pb etc, they have not a props use with
// React-Bootstrap, you have to use them like regular classes
// inside "className"
You'll want to add className="p-5" to the element. This isn't documented in react-bootstrap but it's in the original Bootstrap 4 documentation here: https://getbootstrap.com/docs/4.4/utilities/spacing/#examples
Usually, I'm able to add custom styles to React Bootstrap components by just adding them to the style param. I've put together a short example below, hope this helps.
import React from 'react';
import { Button } from 'react-bootstrap';
const styles = {
myCoolButton: {
paddingTop: "10vh",
paddingBottom: "10vh",
paddingRight: "10vw",
paddingLeft: "10vw"
}
}
const ReactButton = (props) => {
return (
<Button style={styles.myCoolButton} onClick={()=> {
console.log("Do something here!")
}}>Click Me!</Button>
);
}
export default ReactButton
You can also pass custom components (including those from react-bootstrap) into the styled-components constructor if you prefer to do it that way.
None of the jQuery-free implementations of Bootstrap (React Bootstrap, BootstrapVue or ngBootstrap) have implemented utility directives for spacing (margin/padding), simply because Bootstrap have made it unnecessary in the vast majority of cases, by providing a very intuitive set of Spacing utility classes.
All you need to do is apply the desired class.
To apply utility classes selectively, based on responsiveness interval (media queries), you could use a useMedia hook, as demoed here.
In a nutshell:
const interval = useMedia([
"(min-width: 1200px)",
"(min-width: 992px)",
"(min-width: 768px)",
"(min-width: 576px)"
],
["xl", "lg", "md", "sm"],
"xs"
);
(Based on useMedia from useHooks/useMedia).
You can now reuse this hook throughout your app to add media interval based logic.
Example usages:
// interval === 'sm' ? a : b
// ['xs', 'sm'].includes(interval) ? a : b
// negations of the above, etc...
Important: this particular implementation returns the first matching media query in the list.
If you need to map various media queries, to an object/map with true/false values, you'll need to modify getValue fn to return the entire list, along these lines:
const getValue = () => {
const matches = mediaQueryLists.map(mql => mql.matches);
return values.reduce((o, k, i) => ({...o, [k]: matches[i]}), {})
};
Working example here.
Obviously, you could expand on it and add/remove queries. However, be warned each query adds a separate listener so it could impact performance.
In most cases, the return of the first matching query (first example) is enough.
Note: if the above useMedia hook is not enough for your use case, a more robust and heavily tested solution for media-query listeners in JS is enquire.js. It's easy to use, incredibly light and thoroughly tested cross-browser/cross-device. I have no affiliation with it, but I have used it in various projects over the course of more than a decade. In short, I couldn't recommend it more.
Back to Bootstrap 4: in order to customize the $spacer sizes, follow the guide provided under Bootstrap's theming as it's actually about more than what we typically call theming (changing colors), it's about overriding default values of Bootstrap's SASS defaults, including responsivenss breakpoints, spacers, number of columns and many, many others. The one you're interested in is $spacer.
Simply write the overrides into an .scss file and import it in your root component. Example.
Note: a (simpler and more intuitive) option to customize Bootstrap is to do it visually, using bootstrap.build but it's typically a few minor versions behind (i.e. Bootstrap is now at v4.4.1 and the build tool is at v4.3.0).
The build customizer provides intuitive controls and real time visualization.
It allows export as .css or .scss.
Just try this out once according to your input and still if face any issue you can reach out.In below we have increased the .col padding with .px-md-5 and then countered then with .mx-md-n5 on the parent .row.
JSX:
import React from 'react'
import { MDBContainer, MDBRow, MDBCol } from 'mdbreact';
const SpacingPage = () => {
return (
<MDBContainer>
<MDBRow className="mx-md-n5">
<MDBCol size="6" className="py-3 px-md-5">Custom column padding</MDBCol>
<MDBCol size="6" className="py-3 px-md-5">Custom column padding</MDBCol>
</MDBRow>
</MDBContainer>
)
}
export default SpacingPage;
If you still have any kind of doubt on this then feel free to ask .

How would I create a React reusable component in this case?

Well I don't know if I am allow to post a question like this which is obviously more generic. But I just wanted to clarify and understand more about React reusable components. I have a component which holds information to open modals, and to insert user input.
I wanted to create the same component - when it comes to the design - but instead of having inputs and modals I just wanted to display information.
Is it possible for me to use the same visual component with different purposes such as to Input data and Visualize data? How would I do that since the input and the modal component uses logic and its internal state to open modals and uses methods from its parent to handleInputData? how do I switch these functionalities?
Yes, of course. It's the core feature of React, the declarative composition of components.
For instance, let's say that you have a Modal component which handles the display of something on the screen, above other content. You can use the props to customize what it renders right?
Them, you will specialize that component with your different behaviours, like a form or displaying information.
Example (conceptually):
const Modal = ({ title, children }) => (
<div className="modal">
<h1>{ title }</h1>
<div className="body">
{ children }
</div>
</div>
)
const FormModal = () => (
<Modal title="What's your name?">
<form>
{ /* your form here */ }
</form>
</Modal>
)
const AlertModal = () => (
<Modal title="Something happened">
{ /* your information to display here */ }
</Modal>
)

Dynamically changing React component tag

I'm creating a Landing page for a project and want to reduce my code by making a helper function to display my four different paper components. Everything seems to be working correctly except for displaying my Icon components that are within the papers.
When I console log Icon it is the correct text, yet the component doesn't appear on the page and I receive these two warnings for each component tag:
"Warning: The tag <CardTravelIcon> is unrecognized in this browser. If you
meant to render a React component, start its name with an uppercase letter."
and
"Warning: <CardTravelIcon /> is using uppercase HTML. Always use lowercase
HTML tags in React."
If I just hard code in CardTravelIcon or any of the other 3 component names in that exact format instead of using Icon from my map function, everything works as expected. Below is the code for my helper function:
class Landing extends Component {
renderPapers() {
const classes = this.props.classes;
return _.map(infoPapers, ({ description, Icon }) => {
return (
<Grid item xs={6} sm={3} key={Icon}>
<Paper className={classes.paper}>
<Icon className={classes.paperIcons} />
{description}
</Paper>
</Grid>
);
});
}
I'm at a loss and would appreciate any help. Thank you.
So you want to pass a component as a variable, right?
Let's say you have this minimal CardTravelIcon component:
const CardTravelIcon = ( props ) => (
<div className={ props.className }>Card Travel Icon</div>
);
And infoPapers data like this (Icon is a reference to the component):
const infoPapers = [
{
description: "Paper 1 description",
Icon : CardTravelIcon
}];
You didn't show us the infoPapers data, but I suspect you're trying to pass a string as the component, e.g. { Icon : "<CardTravelIcon />" } and expect it to work like setting innerHTML (rendering HTML from a string). This is not the case in React, the JSX code needs to be transpiled into calls to React.CreateElement first, and it isn't done by parsing strings.
If you pass references to components everything should be rendered just fine with the following render method (note: removed lodash in favor of native map method, for clarity):
class Landing extends React.Component {
render() {
return infoPapers.map(({ description, Icon }, idx) => {
return (
<div key={ idx }>
<Icon />
{description}
</div>
);
});
}
};
Here's a working example: https://jsfiddle.net/svygw338/

Resources