I am thinking about the possibility of embedding two imports among map().
My react code looks like this:
{this.state.dataExample.map(item => (
<ItemsSection nameSection={item.name} />
item.data.map((post, index) => (
<ItemsTasks
key={index}
title={post.name}
/>
))
))}
result:
// from ItemsSection
<div className="items-section-name">
<div className="section-name">{nameSection}</div>
</div>
// from ItemsTasks
<div className="item-data">
<div className="item-title">{title}</div>
<div className="item-data">
<div className="item-title">{title}</div>
</div>
This code should illustrate what I would like to get. Trying to import a separate div for each 'element'. The above code reports a syntax error but I have no idea how I could do it.
From the docs,
A common pattern in React is for a component to return multiple elements. Fragments let you group a list of children without adding extra nodes to the DOM.
You can use Fragment, short syntax <></> (It looks like empty tags),
{
this.state.dataExample.map(item => (
<>
<ItemsSection nameSection={item.name} />
{
item.data.map((post, index) => (
<ItemsTasks
key={index}
title={post.name}
/>
))
}
</>
))
}
or you can import Fragment from react package,
import React, {Fragment} from 'react';
{
this.state.dataExample.map(item => (
<Fragment>
<ItemsSection nameSection={item.name} />
{
item.data.map((post, index) => (
<ItemsTasks
key={index}
title={post.name}
/>
))
}
</Fragment>
))
}
You can use React's Fragment
{
this.state.dataExample.map(item => (
<React.Fragment>
<ItemsSection nameSection={item.name} />
{
item.data.map((post, index) => (
<ItemsTasks
key={index}
title={post.name}
/>
))
}
</React.Fragment>
))
}
Related
for some reason, I get the "each child in a list should have unique key" error when returning the following code. I do not understand why this happens, as I specifically assign the key during mapping:
return (
<>
{sortfeedCards(feedCards)}
{loggedIn === true ? (feedCardsMod.map((card, index) => (
<>
<p>{index}</p>
<FeedCard key={index} cardData={card} loggedIn={loggedIn} />
</>
))) : ('')}
</>
)
And here's what the render looks like.. it seems to me that the index-variable does work:
Many Thanks in advance!
The key needs to be on the outermost element, so on the Fragment, not the FeedCard:
feedCardsMod.map((card, index) => (
<React.Fragment key={index}>
<p>{index}</p>
<FeedCard cardData={card} loggedIn={loggedIn} />
<React.Fragment/>
))
(The shorthand syntax <></> for fragments doesn't allow keys, so i switched to using React.Fragment explicitly)
Try this:
return (
<>
{sortfeedCards(feedCards)}
{loggedIn === true ? (feedCardsMod.map((card, index) => (
<div key={index}>
<p>{index}</p>
<FeedCard cardData={card} loggedIn={loggedIn} />
</div>
))) : ('')}
</>
)
Keys must be unique amongst the enclosing tags:
https://reactjs.org/docs/lists-and-keys.html
I have the following list of React components and can't change this format.
How could I render this list on my page by looping over it in some way?
const allComponents = isValid => [
{
Component: (
<ComponentA
isTransparent={true}
/>
),
},
{
Component: (
<div>
{<ComponentB/>}
</div>
),
},
!isValid && {
Component: (
<div>
{<ComponentC/>}
</div>
),
},
].filter(Boolean);
Within my return block tried the following:
return (
<Fragment>
{allComponents(false).map(c => (
{c}
))}
</Fragment>
);
End up with following error.
Error! Objects are not valid as a React child.
(found: object with keys {c}). If you meant to render a
collection of children, use an array instead.
But the above allComponents is an array.
Could I please get some advice on this pls.
The JSX stored in the the array returned by allComponents() needs to be returned from a valid function component. You can either turn the Component properties into functions
{
Component: () => (
<ComponentA />
),
},
// And then call it in the map()
{allComponents(false).map(c => (
c.Component()
))}
or return the JSX from an IIFE inside the map() call
{allComponents(false).map(c => (
(() => c.Component)()
))}
Working snippet
const App = () => {
const allComponents = isValid => [
{
Component: (
<ComponentA />
)
,
},
{
Component: (
<div>
{<ComponentB />}
</div>
)
,
},
!isValid && {
Component: (
<div>
{<ComponentC />}
</div>)
,
},
].filter(Boolean);
return (
<div>
<p>isValid: False</p>
<div>
{allComponents(false).map(c => (
(() => c.Component)()
))}
</div>
<p>isValid: True</p>
<div>
{allComponents(true).map(c => (
(() => c.Component)()
))}
</div>
</div>
);
}
const ComponentA = () => {
return (
<div>Component A</div>
)
}
const ComponentB = () => {
return (
<div>Component B</div>
)
}
const ComponentC = () => {
return (
<div>Component C</div>
)
}
ReactDOM.render(
<App />,
document.getElementById("root")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
return (
<Fragment>
{allComponents(false).map(c => (
{c.component}
))}
</Fragment>
);
you are attempting to render an object in your above example and not the component itself. IMO I would update your overall structure
So I have a toggle looking like this (see below), but the page always re-render the whole thing on the first time I click on the toggle.
export default function Toggle({isChecked, label}: Props) {
return (
<Wrapper>
<Switch isChecked={isChecked}>
<span />
</Switch>
{label}
</Wrapper>
)
}
Then another component which is using this Toggle component
export default function ToggleBox({isChecked, label, children}: Props) {
return (
<Wrapper>
<Toggle isChecked={isChecked} label={label} />
<Content>{children}</Content>
</Wrapper>
)
}
There is a layout
export default function Layout({...someprops bla bla, children}: Props) {
<Wrapper>
<DesktopImg>
<ImageWrapper>
<Image src={image.url} alt={`${headline} image`} layout="fill" />
</ImageWrapper>
</DesktopImg>
<div>
<Content>
{back && backButton}
<MobileImg>
<Image
src={image.url}
alt={`${headline} image`}
width={image.width}
height={image.height}
/>
</MobileImg>
{headline}
<P gutterSize="medium">{description}</P>
</Content>
<ChildrenContainer>{children}</ChildrenContainer>
</div>
</Wrapper>
}
Then finally the page which use the ToggleBox.
export default function Index({isChecked, label, children}: Props) {
const [check, setCheck] = useState(false)
return (
<Layout>
<div onClick={() => setCheck(!check)}>
<ToggleBox label="some label..." isChecked={check}>
//sometext..
</ToggleBox>
</div>
<Button onClick={nextPage} disabled={!check}>
Next
</Button>
</Layout>
)
}
I kinda tried to use the React.memo method but it doesnt seem to work. Any suggestion to make the page not re-render the whole thing but just the toggle?
Move your state further down the tree, you want it to be as close to the component(s) it impacts as possible, again this will probably require breaking out into smaller components, for example, break out the following into a seperate component -
const NewToggleComponent = () => {
const [check, setCheck] = useState(false)
return (
<div onClick={() => setCheck(!check)}>
<ToggleBox label="some label..." isChecked={check}>
//sometext..
</ToggleBox>
</div>
<Button onClick={nextPage} disabled={!check}>
Next
</Button>
)
}
remove state from the top level component, and use this component in your top level component -
...
<NewToggleComponent />
...
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
function App() {
return (
<div>
<Welcome name="Sara" />
<Welcome name="Cahal" />
<Welcome name="Edite" />
</div>
);
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
Is there any way to add attributes to the Welcome function-component, other than by creating a separate line such as <Welcome name="Sara" />?
Using .map() you can render the elements of an array as:
function App() {
const elements = ["Sara", "Cahal", "Edite"]
return (
<div>
{ elements.map((e, i) => <Welcome key={i} name={e} />) }
</div>
);
}
Additionally I suggest to read through the documentation of Rendering Elements and Lists and Keys.
This is not the standard way of defining props, but I quite like the syntax of using an object with the spread operator to define props if you have variables with the names of the props you want.
function App() {
const elements = ['Sara', 'Cahal', 'Edite'];
return (
<div>
{elements.map((name, key) => (
<Welcome {...{ name, key }} />
))}
</div>
);
}
You can create an array with names and after loop through it:
const names = ["Sara", "Cahal", "Edite"];
return (
<div>
{names.map(name => <Welcome key={name} name={name} />)}
</div>
)
UI on a react component. I have a <BottomNavigationItem /> component. This actually renders as an <button>. How can I actually make it render/navigate to a URL?
class FooterNavigation extends Component {
state = {
selectedIndex: 0,
};
select = (index) => this.setState({selectedIndex: index});
render() {
return (
<footer className="mdl-mini-footer">
<Paper zDepth={1}>
<BottomNavigation selectedIndex={this.state.selectedIndex}>
<BottomNavigationItem
label="Reviews"
icon={reviewIcon}
onClick={() => this.select(0)}
/>
</BottomNavigation>
</Paper>
</footer>
);
}
}
Simply you can just add containerElement={<Link to="/home"/>} don't forget to import Link from react-router-dom
So it will be like this:
<BottomNavigationItem
containerElement={<Link to="/home"/>}
label="Reviews"
icon={reviewIcon}
onClick={() => this.select(0)}
/>