Pass Data To A Custom Component - reactjs

I am trying to study this tab feature using ReactJs and seems to be working: Tab in ReactJs
I was wondering if I can pass a data type to the components as follows: Three components for tabs
const TabOne = (data) => {
return (
<p>
{data.map((val: any) => (
val.id
))}
</p>
)
}
In the same time, tried to do the same:
const tabs = [
{
label: 'Opened', // Tab Title - String
Component: TabOne(data) // Tab Body - JSX.Element
},
{
label: 'Closed',
Component: TabTwo
}
]
Or even this one, a silly one:
<Tabs tabs = {tabs(data)} />
Finally got this - Type 'Element' provides no match for the signature '(): Element'. Is there any way I can make use of the above?
N.B: My plan is to show two versions of data in each tab depending upon condition.

Related

How can animate between array filter methods with React?

Im currently building my personal Portfolio and I have an array of objects containing multiple projects, each one of the project object contain a property called category, which can have a value of 'Visual' or 'Complexity'.
My plan is to add two buttons, one for each category, but I would like to animate between the category changes, a simple fade out and fade in would be nice, any idea how can I do this ?
I tried using React Transition Group for this, but didn't manage to figure it out.
The first Component is the ProjectUl, this component will receive a filter prop, which is basically a string indicating which category should the filter method use.
const projects = [
{
name: "Limitless",
category: "visual",
dash: "- Landing Page",
img: imgList.limitless,
gif: imgList.limitlessGif,
},
{
name: "Spacejet",
category: "complexity visual",
dash: "- Landing Page / API Project; ",
img: imgList.spacejet,
},
];
export const ProjectsUl: FC<IProps> = ({ filter }) => {
const [filtered, setFiltered] = useState<IProject[]>([])
useEffect(() => {
const filteredProjects = projects.filter((i) => i.category.includes(filter));
setFiltered(filteredProjects);
}, [filter]);
return (
<ProjectsUlStyle>
{filtered.map((i) => (
<ProjectsLi filtered={i} />
))}
</ProjectsUlStyle>
);
};
Then, inside the ProjectsUl there will be the ProjectsLi, which are the list of projects, here is the code for the ProjectsLi
export const ProjectsLi: FC<any> = ({ filtered }) => {
return (
<LiStyle>
<img src={filtered.img} />
<div>
<span className="dash">{filtered.dash}</span>
<header>
<h1>{filtered.name}</h1>
<FAicons.FaGithub />
<FAicons.FaCode />
</header>
</div>
</LiStyle>
);
};

How to pass props to React child components whose required types we don't know yet

Is it possible to pass props down to children components whose required types we don't yet know? Something like this:
interface CardProps<T> {
set: SetProps<T>;
setSet: Dispatch<SetStateAction<SetProps<T>>>;
children: ReactNode;
}
const RenderCards = <T extends object>({ set, setSet, children }: CardProps<T>) => (
<>
{set &&
set.data &&
set.data.map((item: T, idx: number) => (
<SwipeBox
key={idx}
state={{ set, setSet }}
>
<MovieCard movie={item as MovieType} /> // This is too specific, want to delete.
{children ...props} // This is flexible, but wrong.
</SwipeBox>
))}
</>
);
So far, I've come up with Context API as a viable solution. It's certainly less boilerplate than Redux but, is there an even easier way?
I'm guessing a bit about your intentions, but I am interpreting this as:
You want to support rendering different kinds of cards for different T types.
You want to pass through certain props to every individual card.
I came up with a solution based on a render props pattern. We now have two generics -- T which is still the item type and Extra which is the props that we pass through.
Each individual card will receive the properties of the item as props, all of the Extra props, and set and setSet (not sure if those last two are actually needed).
The card group requires set, setSet, the Extra props, and a Render component for the individual card.
import React, { Dispatch, SetStateAction, ComponentType, useState } from "react";
interface SetProps<T> {
data: T[];
}
interface CardProps<T> {
set: SetProps<T>;
setSet: Dispatch<SetStateAction<SetProps<T>>>;
}
type CardGroupProps<T, Extra = {}> = Extra &
CardProps<T> & {
Render: ComponentType<T & Extra & CardProps<T>>;
};
const CardGroup = <T extends object, Extra extends object>(
{set, setSet, Render, ...extra}: CardGroupProps<T, Extra>
) => (
<>
{set.data.map((item: T, idx: number) => (
<SwipeBox
key={idx}
state={{ set, setSet }}
>
<Render
set={set}
setSet={setSet}
{...(extra as Extra)}
{...item}
/>
</SwipeBox>
))}
</>
);
Here's a silly example to show usage. Here our RenderMovieCard component requires the Movie item and also a color prop. You will get an error if you try to call a CardGroup with Render={RenderMovieCard} without passing this required color prop.
interface Movie {
title: string;
}
const RenderMovieCard = ({ title, color }: Movie & { color: string }) => (
<div style={{ color }}>{title}</div>
);
export default () => {
const [movies, setMovies] = useState<SetProps<Movie>>({
data: [{ title: "Jaws" }, { title: "Star Wars" }]
});
return (
<CardGroup
set={movies}
setSet={setMovies}
Render={RenderMovieCard}
color="red"
/>
);
};
Code Sandbox

Display react components in grid structure

I have a React application that is displaying a number of buttons in a modal that form part of a button group.
The values for these buttons are set up in the state object as shown below.
At the moment these buttons display within my modal each on a separate line one after the other.
I would like to have them displayed in a grid type structure. As there are 5 of them this might be 2 on the first 2 lines and then the last one
on the third line perhaps centered if possible.
How could I go about doing this? Sorry I realise I've not offered a solution attempt for this but I'm not sure where to start. I've been searching online
and can't find any examples that match what I am trying to do i.e. where the actual data for the table is set in state. I will continue to do more research but thought I'd ask on here to see if someone could offer any tips.
const marginSelectionControls = [
{ label: '21+', type: '21plus' },
{ label: '16-20', type: '16to20' },
{ label: '11-15', type: '11to15' },
{ label: '6-10', type: '6to10' },
{ label: '1-5', type: '1to5' }
];
const MarginSelectionControls = (props ) => (
<div className="btn-group">
<ButtonGroup toggle={this.toggle}>
{marginSelectionControls.map( ctrl => (
<MarginSelectionControl
key={ctrl.label}
label={ctrl.label}
selectMargin={(winningMargin) => props.selectMargin(ctrl.label)}
selectedmargin={props.selectedmargin}
/>
))}
</ButtonGroup>
</div>
);
##########################################
const MarginSelectionControl = (props) => {
const MarginSelectionControlClasses = [classes.PredResSelectControl];
if (props.selectedmargin === props.label) {
MarginSelectionControlClasses.push(classes.Less);
}
else {
MarginSelectionControlClasses.push(classes.More);
}
return (
<div className={classes.MarginSelectionControl}>
<button
type="button"
label={props.label}
className={MarginSelectionControlClasses.join(' ')}
onClick={props.selectMargin}
selectedmargin={props.selectedmargin}
>{props.label}</button>
</div>
)
};

How can I display a Persona component in a CommandBar in React Fabric-UI?

I am trying to display a Persona component on the far right of my CommandBar component, which I use as a header for my application.
Here's a code snippet
const getFarItems = () => {
return [
{
key: 'profile',
text: <Persona text="Kat Larrson" />,
onClick: () => console.log('Sort')
}
]
}
const FabricHeader: React.SFC<props> = () => {
return (
<div>
<CommandBar
items={getItems()}
farItems={getFarItems()}
ariaLabel={'Use left and right arrow keys to navigate between commands'}
/>
</div>
);
}
This throws a type error because the text prop expects a string and not a component. Any help would be appreciated!
Under the ICommandBarItemProps there is a property called commandBarButtonAs that the docs state:
Method to override the render of the individual command bar button.
Note, is not used when rendered in overflow
And its default component is CommandBarButton which is basically a Button
Basically there are two ways to do this.
Keep using Button, and apply your own renderer. Basically the IButtonProps you can add onRenderChildren which would allow you to add any Component such as Persona to render. This example would show you how it is done https://codepen.io/micahgodbolt/pen/qMoYQo
const farItems = [{
// Set to null if you have submenus that want to hide the down arrow.
onRenderMenuIcon: () => null,
// Any renderer
onRenderChildren: () => ,
key: 'persona',
name: 'Persona',
iconOnly: true,
}]
Or add your own crazy component not dependent on CommandBarButton but that means you need to handle everything like focus, accessibility yourself. This example would show you how it is done https://codepen.io/mohamedhmansour/pen/GPNKwM
const farItems = [
{
key: 'persona',
name: 'Persona',
commandBarButtonAs: PersonaCommandBarComponent
}
];
function PersonaCommandBarComponent() {
return (
);
}

React High Order Components

Lets says I have an array of objects where each object have structure like below
obj = {
name:"Name1",
description:"Description1",
activeState:1,
rating:5
}
const User = (obj) => {
let userActiveState = (obj.activeState === 1) ? 'Active' : 'Non Active';
return (
<tr>
<td>{obj.name}</td>
<td>{obj.description}</td>
<td>{userActiveState}</td>
</tr>
);
}
User.propTypes = {
name: PropTypes.string
description: PropTypes.string
activeState: PropTypes.number
}
User.defaultProps = {
name: "Not Available"
description:""
activeState: 0
}
I use this array to create UI using User(a stateless functional react component), but before the stateless functional react component spits out the UI I want to make some modification to the object properties which are required by the
UI (example using text instead of number for activeState) and not all the object properties are required too.
Where would I remove unwanted properties so that I can have defaultProps and proptypes defined only for the required properties and would I use a high order component which transforms and filters the obj properties?
You don't need a HoC here - a simple composition is enough:
const Component = ...;
const ComponentButDifferentFormats = ({propToSkip, propToRename, ...props}) => (
<Component
{...props}
propRenamed={propToRename}
propX={parseFloat(props.propX)}
propY={'' + props.propY}
/>
);
With this approach, you'll decouple the transformation logic from the real UI. It's really useful for example with an API response. Creating a HoC is also an option: it might be parametrized with formats, filters or even the component itself. One more function in the above example: Component => ....

Resources