I am creating a wrapper component for icons that I import using react-icons. Here is an example of how it looks right now:
import { FaTwitter as Twitter} from 'react-icons/fa'
import { Icon } from './elements
<Icon>
<Twitter />
<Icon>
Now, this works just as I want it to -- but I would like to simplify the code. Ideally, I'd like it to look/work like this:
<Icon name='twitter' />
Any idea how to do this?
NOTE: In case it helps, here is current code for my Icon component:
export const Icon = props => <IconBase {...props} />
The <IconBase> component is just some styles from styled-components.
UPDATE
I just want to note that the Twitter example is just that -- an example. I'm looking for a solution that will work no matter what name I pass to the <Icon> component. So, in other words, all of the following (and more) will work:
<Icon name="Facebook" />
<Icon name="Search" />
<Icon name="Menu" />
Each of these would be equivalent to:
<Icon><Facebook /></Icon>
<Icon><Search /></Icon>
<Icon><Menu /></Icon>
In other words, no matter what icon I pull in from react-icons, it will render properly vis-a-vis the name prop.
What about this?
// definition:
const Icon = (props) => <SomeIconWrapper><props.glyph /></SomeIconWrapper>;
// usage:
<Icon glyph={Twitter} />
It is super simple and flexible, no need for any dictionary or so.
I think something like this would satisfy your condition.
const App = () => <Icon name="twitter" />;
const dict = { twitter: <Twitter /> };
const Icon = ({ name }) => <IconBase>{dict[name]}</IconBase>;
Related
I have the following code which I'm trying to refactor
const [edit, setEdit] = useState(false);
<ListItemText
primary={edit ?
<TextareaAutosize ... />
: <Typography ..../>}
/>
The TextareaAutosize repeats a lot through the app so I thought I would convert it into a separate component.
export default function Textarea(props) {
const [edit, setEdit] = useState(false);
if(edit){
return(
<TextareaAutosize .../>
)
}
return false
}
As you can see, if edit is false the component returns false. The back at the top I thought I would do this
import Textarea from "../Textarea";
<ListItemText
primary={Textarea ?
<Textarea ... />
: <Typography ..../>}
/>
By my logic, there should be a way to check if component Textarea will return false, right?
A "component" (JSX) is a UI element. You must return JSX or null, and the rendering engine will render the returned JSX or nothing if null.
You can check a flag and short-circuit:
{isFlag && <MyComponent ... />}
or have the component render or not (or if you want to keep state just show/hide):
<MyComponent isVisible={isFlag} />
Or possible return different components depending on flags:
if (isLoading) {
return <MyLoadingSkeletonComponent />
}
<MyMainUIComponent />
EDIT:
You may want to refactor into a compound component where you take the flag and hide the show/hide logic within it
const TextArea = ({edit, editMode, viewMode}) => (
edit ? editMode : viewMode
)
// Call it with the flag and both components:
<TextArea
edit={edit}
editMode={<TextareaAutosize ... />}
viewMode={<Typography ... />}
/>
Have the best of the two worlds, your idea of refactoring is correct, but it is missing something.
try something like this:
export default function Textarea(props) {
props.edit ? <TextareaAutosize .../> : <Typography ..../>
}
and
<ListItemText
primary=<TextareaAutosize {edit} ... />
/>
In this case you have one place to change TextareaAutosize and Typography codes, less messy code in parent listing.
Hope this helps.
I'm currently working on an admin portal using react-admin, and I've been able to seamlessly style it using MaterialUI, specifically its makeStyles hook. The way I've done it is I'd import my makeStyles file that looks similar to this:
export const detailsView = makeStyles({
detail: {
width: "100%",
"& div": {
display: "Block",
visibility: "Visible",
}
}
export default detailsView
into my main component, that would hold, for example, a List component like this:
export const ExampleList = (props) => {
const classes = importedStyles();
return (
<>
<h2 className={classes.tableTitle}>Example Header</h2>
<List {...props} className={classNames(classes.table)}>
<Datagrid rowClick="edit">
<ReferenceField source="id" reference="users" label="Name">
<FunctionField
label="Name"
render={(record) => `${record.first_name} ${record.last_name}`}
/>
</ReferenceField>
<TextField source="title"/>
<DateField source="date" />
</Datagrid>
</List>
</>
);
};
export default ExampleList;
If I had to wrap my own div that would also hold a section of a TextField, everything still works according to plan. However, this is only the case with the List, Edit, Filter, and Create, however, I'm unable to properly style the Show component.
Prior to adding any styles or wrapping some fields up in a div, this is how it would look like: Notice how the name shows up just fine.
However, when I wrap the Person Details header with the rendered name, as seen below:
<div className={detailClasses.detailSection}>
<h3 className={ detailClasses.detailSectionTitle}>Person Details</h3>
<ReferenceField
source="id"
reference="users"
label="Name"
className={detailClasses.detailSectionInfo}
>
<FunctionField
render={(record) => `${record.first_name} ${record.last_name}`}
/>
</ReferenceField>
</div>
then the information that I want rendered (in this case, the person's name), then it completely stops rendering and doesn't show up on the page.
This hasn't happened with any other react-admin component that I mentioned somewhere above.
I was wondering why this is the case, and why it is only happening with the Show component.
Thanks in advance!
I started using javascript and React for a small project based on REST. So I tried to show some datas from my database in a browser, but only the last Product shows up 7 times (only 7 products are in the database). And additionally the DeleteButton don't want to show up, and when I try to have a look on a product from web browser (through EditButton), it says Element does not exist. This last should be because it want to redirect http://localhost:5000/orders/undefined. So maybe it can't get the ID of a product?
Here is the code for the DeleteButton part:
import React from 'react';
import {List, Datagrid, TextField, NumberField, ImageField, EditButton, DeleteButton} from 'react-admin';
const ProductList = (props) => {
return <List {...props}>
<Datagrid>
<TextField label = 'ID' source = '_id' />
<TextField source = 'title' />
<NumberField source = 'year' />
<TextField source = 'author' />
<ImageField source = 'productImage' />
<EditButton basePath = '/products' />
<DeleteButton basePath = '/products' />
</Datagrid>
</List>
};
export default ProductList;
Thanks,
I am new to react-native. Here I am trying to add two buttons on headerRight. I did add one button but I could not figure out how to put more than one. Something like this.
I am using react-navigaiton and react-navigation-header-buttons.
This is how I added one button.
mainScreen
headerRight: (
<HeaderButtons HeaderButtonComponent={CustomHeaderButton}>
<Item
title={"Search"}
iconName={"md-search"}
onPress={() => {
console.log('Search')
}}
/>
</HeaderButtons>
),
CustomHeaderButton.js
import {HeaderButton, Item} from 'react-navigation-header-buttons';
import {Ionicons} from '#expo/vector-icons';
const CustomHeaderButton = props => {
return(
<HeaderButton
{...props}
IconComponent={Ionicons}
iconSize={23}
color={'black'}
/>
)
};
export default CustomHeaderButton;
You're on the right track. You should be able to simply add another Item with whatever title, icon, onPress functionality you want wrapped in the HeaderButtons component like this:
<HeaderButtons HeaderButtonComponent={CustomHeaderButton}>
<Item
title={"Search"}
iconName={"md-search"}
onPress={() => {
console.log('Search')
}}
/>
<Item
title={"Other Button"}
iconName={"other-icon-name"}
onPress={() => {
console.log('The other header icon was pressed.')
}}
/>
</HeaderButtons>
You are able to nest multiple React elements within a React element, which is what this example uses. For instance, you can nest multiple Text elements inside of a View.
It looks like you are using the react-navigation-header-buttons package, here is their example with multiple header icons for your reference as well: https://github.com/vonovak/react-navigation-header-buttons/blob/master/example/screens/UsageCustom.tsx
I have a User Resource, which referenced by many other resources.
So I want to create a UserResourceInput :
import React from 'react';
import {ReferenceInput, SelectInput} from 'admin-on-rest';
const UserReferenceInput = (props) => (
<ReferenceInput reference="user" {...props}>
<SelectInput optionText="name"/>
</ReferenceInput>
);
UserReferenceInput.defaultProps = {
source: 'userId',
addLabel: true,
label: 'User'
};
export default UserReferenceInput;
And Use it in simple form like this:
ProductCreate = (props) => (
<Create {...props}>
<SimpleForm>
<TextInput source="title" />
<NumberInput source="price" />
<UserReferenceInput />
</SimpleForm>
</Create>
);
But I get this Error:
You are missing the source prop on the ReferenceInput. Hence, it can't find value for it. You can define it either inside the UserReferenceInput directly or pass it as prop to the UserReferenceInput in your form.
Edit
Don't use the addLabel prop on the ReferenceInput, it does not support it. Instead, apply it on the SelectInput child.