<div class='row m-b-0'>
<div class="col-sm-6 col-md-4">...</div>
<div class="col-sm-6 col-md-4">...</div>
<div class="col-sm-6 col-md-4">...</div>
</div>
I am used to using jQuery when I implement like jQuery inside reactjs but in react can not render.
Below is my code.
How can I solve it?
render(){
let tag1 = '';
let tag2 = '';
const wrapper = (value,i) => {
if(i === 1 || i === 4 || i === 7 || i === 10 || i === 13){
tag1 = "<div class='row m-b-0'>";
} else {
tag1 = '';
}
if(i === 3 || i === 6 || i === 9 || i === 12 || i === 15){
tag2 = "</div>";
} else {
tag2 = '';
}
return (<Content data={i} value={value} tag1={tag1} tag2={tag2} />)
}
return(
<Fragment>
{
this.state.data.map((value,i) =>
wrapper(value,i)
)
}
</Fragment>
)
}
}
const Content = (props) => {
return(
<Fragment key={props.data}>
{
props.tag1
}
...
{
props.tag2
}
</Fragment>
)
}
It's possible to render 'raw html' in react (f.e. dangerouslySetInnerHTML or fragments) but using react to glue strings/html partials is a bad practice.
React creates (virtual) nodes (fragment) with restrictions - I'm affraid it can't contain tag opening and closing in another node.
You have to structure components closer to required html. In this case (you didn't show data structure) I would divide data in 3-elements sets returning complete ('row') structure/fragment in one step:
return (
<div class='row m-b-0' key={i}>
<div class="col-sm-6 col-md-4">{subset[0]}/div>
<div class="col-sm-6 col-md-4">{subset[1]}/div>
<div class="col-sm-6 col-md-4">{subset[2]}/div>
</div>
)
Then you can refactor further:
return (
<div class='row m-b-0' key={i}>
{subset.map((value,i) => (
<div class="col-sm-6 col-md-4" key={i}>{value}</div>
)}
</div>
)
and later
return (
<div class='row m-b-0' key={i}>
{subset.map((value,i) => renderCell(value,i) )}
/div>
)
and probably making Cell component
return (
<Row ...props.rowProps key={i}>
{subset.map((value,i) => <Cell value={value} i={i} ...props.cellProps/> )}
</Row>
)
or if you need simple conditional depth
if(!!props.someCond) return (
<Row ...props.rowProps key={i}>
{subset.map((value,i) => <Cell value={value} i={i} ...props.cellProps/> )}
</Row>
}
return (
<Fragment key={i}>
{subset.map((value,i) => <Cell value={value} i={i} ...props.cellProps/> )}
</Fragment>
}
or in JSX, sth like:
return (
{!!props.someCond ?
<Row ...props.rowProps key={i}>
: <Fragment key={i}>}
{subset.map((value,i) => <Cell value={value} i={i} ...props.cellProps/> )}
{!!props.someCond ? </Row> : </Fragment> }
)
from some time you can return more than one node and sth like this should work:
return (
{!!props.someCond && <Row ...props.rowProps key={i}>}
{subset.map((value,i) => <Cell value={value} i={i} ...props.cellProps/> )}
{!!props.someCond && </Row> }
)
There are many possibilities but you have to 'think in react', more structured way ;)
PS. use modulo operator to simplify condition
const openingTag = (i>0 && (i % 3 === 1)); // 1,4,7...
const tag1 = openingTag ? `<div class='row m-b-0'>` : null; // null renders nothing in react
having prepared boolean value in jsx you can:
{openingTag && <div class='row m-b-0'>}
but probably it won't work without closing - use it for entire components or (structured) blocks.
Related
i have this function in javascript:
export const commonRenderer = (option, useFormatter, hasSubLabel) => {
if (useFormatter && hasSubLabel) {
return (
<React.Fragment>
<FormattedMessage id={option.label} /><br /><FormattedMessage id={option.subLabel} />
</React.Fragment>
);
}
if (!useFormatter && hasSubLabel) {
return (
<React.Fragment>
{option.label}<br />{option.subLabel}
</React.Fragment>
);
}
if (useFormatter && !hasSubLabel) {
return (
<FormattedMessage id={option.label} />
);
}
return option.label;
};
and somehow i want to simplify this seems it looks really odd to me but im afraid of losing some cases. Any help?
Not sure if it's simpler or not, but you may try something like this:
export const commonRenderer = (option, useFormatter, hasSubLabel) => {
const Element = useFormatter ? FormattedMessage : React.Fragment;
const attr = useFormatter ? 'id' : 'children';
return (
<React.Fragment>
<Element {...{ [attr]: option.label }} />
{hasSubLabel && (
<React.Fragment>
<br />
<Element {...{ [attr]: option.subLabel }} />
</React.Fragment>
)}
</React.Fragment>
);
};
The problem is I have two redux stores
items(Items Store
quotationItems(Quote Items.
When a product item is added to quotationItems I Would to show <RedButton title="Remove" /> or when the quotationItems is empty the <AddButton title="Add" /> should be shown.
using if statement tends to re-render the component and adds new components e.g: After adding a new product to quotation items, there will be a new <AddButton /> in FlatList Component.
interface IProps {
items: ItemInterface[];
documentItems: ItemInterface[];
onAddItem: any;
}
const ItemFlatList2: FC<Partial<IProps>> = ({
items,
documentItems,
onAddItem,
}) => {
const TestView = (itemCode) => {
documentItems.map((x) => {});
};
return (
<FlatList
data={items}
keyExtractor={(item) => item.itemCode.toString()}
renderItem={({
item: { itemCode, itemDescription, itemSellingPrice },
}) => {
return (
<div className={styles.itemContainer}>
<h4>Item Code: {itemCode}</h4>
<h4>Description: {itemDescription}</h4>
<div>
{documentItems.map((x) => {
x.itemCode === itemCode ? (
<RedButton title={"Remove"} key={itemCode} />
) : (
<AddButton title={"Add"} key={itemCode} />
);
})}
</div>
</div>
);
}}
/>
);
};
Other options I've tried:
I've also tried this, still doesn't work, the buttons will show up but after clicking on the first button, which will successful add the product item to quotation item store but when I try and click on the 2nd or 3rd button of `<AddButton title={'Add'} key={itemCode} /> I get no response.
<div>
{documentItems.length <= 0 ? (
<AddButton
title={"Add"}
key={itemCode}
onClick={() => onAddItem(itemCode)}
/>
) : (
documentItems!.map((x) =>
x.itemCode === itemCode ? (
<RedButton title={"Remove"} key={itemCode} />
) : (
<
AddButton title={"Add"} key={itemCode} onClick={() => onAddItem(itemCode)} />
)
)
)}
</div>
This is the result of the modified code above:
Please add the return keyword.
documentItems.map((x) => {
return (x.itemCode === itemCode ? (
<RedButton title={"Remove"} key={itemCode} />
) : (
<AddButton title={"Add"} key={itemCode} />
);
)})
Or Just remove the curly braces.
documentItems.map((x) => (x.itemCode === itemCode ? (
<RedButton title={"Remove"} key={itemCode} />
) : (
<AddButton title={"Add"} key={itemCode} />
)))
Based on the updations that you did in the questions. It is an issue with the data in "documentItems". Since you only need 1 button per item code. Instead of map use find. It will return 1 item and fix this duplicacy.
I am trying to map a return statement with multiple child components and getting ESLint error
console.error
Warning: Each child in a list should have a unique "key" prop.
This is my React Code:
const EmployeeDetails = ({ employeeid }) => {
return (
<div>
<strong>Employee Overview Details</strong>
</div>
<div className="flex-container" key="test">
{employeeOverviewDetails.map((detail, index) => {
return (
<>
{detail.heading === 'Employee ID' && (
<div
className="indiviual-flex"
key={index}
>
<small key={detail.heading}>
{detail.heading}
</small>
<br />
<strong key={detail.value}>
{employeeid}
</strong>
</div>
)}
{detail.heading !== 'Employee ID' && (
<div
className="indiviual-flex"
key={detail.heading}
>
<small>{detail.heading}</small>
<br />
<strong>{detail.value}</strong>
</div>
)}
</>
)
})}
</div>
)
}
I am passing key for every element and yet ESLint keeps warning about unique "key" prop
You are missing a fragment:
const EmployeeDetails = ({ employeeid }) => {
return (
<>
<div>
<strong>Employee Overview Details</strong>
</div>
<div className="flex-container" key="test">
{employeeOverviewDetails.map((detail, index) => {
return (
<>
{detail.heading === "Employee ID" && (
<div className="indiviual-flex" key={index}>
<small key={detail.heading}>{detail.heading}</small>
<br />
<strong key={detail.value}>{employeeid}</strong>
</div>
)}
{detail.heading !== "Employee ID" && (
<div className="indiviual-flex" key={detail.heading}>
<small>{detail.heading}</small>
<br />
<strong>{detail.value}</strong>
</div>
)}
</>
);
})}
</div>
</>
);
};
You cannot have 2 elements side by side in React, either use this syntax
<> </>
to wrap around the elements which are side by side or use you can import Fragment from React like this:
import { Fragment } from "react";
And then wrap the elements which are side by side with Fragment like this:
<Fragment></Fragment>
or if u don't want to import Fragment you can also use React.Fragment. but you need to import react for this.
When I write this code I have an error:
React Hook "useRef" cannot be called inside a callback. React Hooks must be called in a React function component or a custom React Hook function
What should I do with this code?
return ITEMS.map((item, i) => {
const elementRef = useRef(null);
return (
<div
ref={elementRef}
key={i}
>
<p>{item.name}</p>
<Wrapper>
{item.name === visibleItem && (
<Item
parentRef={elementRef}
/>
)}
</Wrapper>
</div>
);
}
Here are two possibilities, Either using useRef with an object/array, or using createRef as suggested by Yevgen Gorbunkov.
I'm not entirely sure as to the viability of these as the createRef option will create entirely new refs on each render, and the useRef option you'll need to make sure your keys/indexes are always the same.
const ITEMS = [{ name: "test" }, { name: "test2" }];
export default function App() {
const ref = useRef({});
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
{ITEMS.map((item, idx) => {
return (
<div key={idx} ref={element => (ref.current[idx] = element)}>
<p>{item.name}</p>
<Wrapper>
{item.name === visibleItem && (
<Item parentRef={ref.current[idx]} />
)}
</Wrapper>
</div>
);
})}
{ITEMS.map((item, idx) => {
const ref = createRef();
return (
<div key={idx} ref={ref}>
<p>{item.name}</p>
<Wrapper>
{item.name === visibleItem && <Item parentRef={ref} />}
</Wrapper>
</div>
);
})}
</div>
);
}
As you can see in my code example below which is part of a render() block in a react component, I am trying to render the value of the variable "folder" in the outer loop. Unfortunately, the code section
<div>{folder}</div>
seems to be ignored. Can anyone help me in finding the right syntax that outputs the current folder value from the outer loop?
{
folders.map((folder,_index1) => {
<div>{folder}</div>
return (
items.map((item, index) => {
return (
<div>
{(folder === item.folder) ?
<Draggable
key={item.id}
draggableId={item.id}
index={index}>
{(provided, snapshot) => (
<div
ref={provided.innerRef}
{ ...provided.draggableProps }
{ ...provided.dragHandleProps }
style={getItemStyle(
snapshot.isDragging,
provided.draggableProps.style
)}>
<div>
{item.content}
</div>
</div>
)}
</Draggable>
: null
}
</div>
)})
)})
}
Following Zydnar's comment above:
This is what it should look like:
{
folders.map((folder,_index1) => {
return (
<> // or <React.Fragment> with the corresponding closing tag
<div>{folder}</div> // this has to be part of what is returned
items.map((item, index) => {
return (
<div>
{(folder === item.folder) ?
...
</>
)})
)})
}