I'm pulling in data from a GraphQL query and mapping through the array in my React app, I can see if I console log the array that all the data is there as requested but when I map through it, I just get nothing showing on my screen, no error, it doesn't generate any HTML elements or anything despite being similar to every other array map I've done so far.
My the mapping part of my component is as follows:
const CareerFeed = React.forwardRef((props, ref) => {
return (
<CareerFeedWrapper ref={ref}>
<Container width={14}>
{console.log(props.array)}
{props.array.map((item, index) => {
<CareerItem key={index}>
{item.title}
</CareerItem>
})}
</Container>
</CareerFeedWrapper>
)
})
You are not returning anything from the .map function: when you use curly brackets, the arrow function no longer implicitly returns. You will need to use the return statement:
{props.array.map((item, index) => {
return (
<CareerItem key={index}>
{item.title}
</CareerItem>
);
})}
Alternatively, ditch the curly brackets and wrap the returned JSX in parenthesis to take advantage of explicit returns:
{props.array.map((item, index) => (
<CareerItem key={index}>
{item.title}
</CareerItem>
))}
Looks like a missing return statement on the map. This means its actually iterating through the array and replacing each one with a null object. Try this:
return (
<CareerFeedWrapper ref={ref}>
<Container width={14}>
{console.log(props.array)}
{props.array.map((item, index) => {
return (<CareerItem key={index}> //added return
{item.title}
</CareerItem>) //added closing parentheses for return
})}
</Container>
</CareerFeedWrapper>
)
})
Related
I'm trying to build a React select component that can support multiple different child component types.
I'd like to do something like this:
export const GenericSelect = (props) => {
const { component, items } = props;
return <>{items && items.map((item, index) => <component id={items.id} name={item.name} />)}</>;
};
And then be able to use it like:
<GenericSelect component={NonGenericCard} items={items} />
Where NonGenericCard supports a fixed set of properties (e.g., id, name), which will be populated from values in the items object.
I tried this, but it doesn't seem like it can create the <component/> at run-time.
Is this possible in Javascript? If so, how can it be accomplished?
In JSX, lower-case tag names are considered to be HTML tags. So you should use Component instead of component.
Also id should be item.id instead of items.id and you should give each element a key.
export const GenericSelect = (props) => {
const { Component, items } = props;
return (
<>
{items &&
items.map((item, index) => (
<Component key={item.id} id={item.id} name={item.name} />
))}
</>
);
};
<GenericSelect Component={NonGenericCard} items={items} />
https://reactjs.org/docs/jsx-in-depth.html#user-defined-components-must-be-capitalized
Is it possible to compose more different parts of component to variable?
documentation
const App = () => {
let element;
element = <View>
<Text>text</Text>
</View> // --> OK
element = element + <View>
<Text>text2</Text>
</View> // --> TypeError: Cannot read properties of undefined (reading 'height')
element.push(<View>
<Text>text3</Text>
</View>); // --> TypeError: element.push is not a function
return <>
{element}
</>
}
export default App;
I use reactjs 17.0.2, typescript and "#react-pdf/renderer": "2.3.0".
Update
Based on your question here, this should work:
<Document>
<Page size="A4" orientation="landscape">
{/* -- Table LEFT: -- */}
<View>
{/* -- Table Head: -- */}
<View>
<Text>Index</Text>
<Text>Brand</Text>
<Text>Type</Text>
</View>
{/* -- Table Body: -- */}
{data?.cars?.length &&
data.cars.map(({ id, brand, type }, index) => (
<View key={`${id}-left`}>
<Text>{index + 1}</Text>
<Text>{brand || ''}</Text>
<Text>{type || ''}</Text>
</View>
))}
</View>
</Page>
<Page size="A4" orientation="landscape">
{/* -- Table RIGHT: -- */}
<View>
{/* -- Table Head: -- */}
<View>
<Text>Color</Text>
<Text>Fuel</Text>
</View>
{/* -- Table Body: -- */}
{data?.cars?.length &&
data.cars.map(({ id, color, fuel }) => (
<View key={`${id}-right`}>
<Text>{color || ''}</Text>
<Text>{fuel || ''}</Text>
</View>
))}
</View>
</Page>
</Document>
The issue seems to be with how you're handling arrays, not with rending React elements.
If you want to access the properties of the object in an array element, you can destructure the element, so instead of
data.cars.map((car, index) => (<Text>{car.color}</Text>))
you can do
data.cars.map(({id, brand, type, color, fuel}, index) => (<Text>{color}</Text>));
If you're not performing any operations on the array elements, you can use an implicit return instead of an explicit return:
// explicit return
data.cars.map(({id, brand, type, color, fuel}, index) => {
// do something else here
return (
<Text>{color}</Text>
)
});
// implicit return
data.cars.map(({id, brand, type, color, fuel}, index) => (<Text>{color}</Text>));
Also, when you're rending known text values in React, you don't need to wrap it in curly braces ({}), you can just render the text directly.
Instead of
<Text>{'color'}</Text>
you can just put
<Text>color</Text>
unless it's required by whatever library you're using. I'm not familiar with #react-pdf/renderer.
One more thing to keep in mind is that the key for list items in React should be something stable. Using array indices as keys is discouraged (see React docs).
Original answer
If you want to render an element this way, you could do something like this:
const App = () => {
let element = [];
// Each child in a list needs a unique "key" prop
element.push(<View key={someUniqueKey}>
<Text>text</Text>
</View>)
element.push(<View key={someOtherUniqueKey}>
<Text>text2</Text>
</View>)
element.push(<View key={oneMoreUniqueKey}>
<Text>text3</Text>
</View>);
return <>
{element}
</>
}
export default App;
Personally, I haven't seen anyone render components like this.
The strategy you are looking for is called conditional rendering, and there are different ways to do this depending on the situation.
For example, if you're trying to dynamically render data from an API response, you could do something like this:
const App = () => {
const { data } = fetchDataFromAPI();
return (
<>
<View>
<Text>text</Text>
</View>
{data?.text2 && (
<View>
<Text>{data.text2}</Text>
</View>
)}
{data?.text3 && (
<View>
<Text>{data.text3}</Text>
</View>
)}
</>
);
};
export default App;
You can check out the React docs for conditional rendering and rendering lists.
(Note: The above links are for the beta docs. If you prefer the classic(?) docs: conditional rendering and lists)
I know about key prop, so i made it in listitem component
const ListItem = ({item}) => {
const {result, time, id} = item;
return(
<li key={id} className='list__item'>
<span className='item__result'>{result} cps</span>
<span className='item__date'>{time}</span>
<button className='item__delete'>delete</button>
</li>
)}
And here is component, where I use it
const Leadboard = () => {
const [data, setData] = useState([{result:'5,63', time:'08.06.2022', id: (new Date()).toString(16)}, {result:'5,63', time:'08.06.2022', id: +(new Date() - 1)}, {result:'5,63', time:'08.06.2022', id: +(new Date() - 2)}]);
let elements=data.map(item => {
return (
<>
<ListItem item={item} />
</>
)
});
return(
<div className='app-leadboard'>
<span className='app-leadboard__title'>Your's best results:</span>
<ol className='app-leadboard__list' type='1'>
{elements}
</ol>
</div>
)}
But after render I still see "key prop" error
I spent so much time on this, but can't understand what's wrong. So smb, help pls with it
You’ve got the wrong list. It’s the <ListItem> components that need the key. (And you can get rid of the react fragments around them because they are pointless).
React first accesses the empty bracket (<> </> ) before accessing the key attribute in your child component.
So you need to either
Make use of the empty brackets and pass the key attribute to it
// Use React.Fragment
let elements=data.map(item => { return
(
<React.Fragment key={item.id}>
<ListItem item={item} />
</React.Fragment>
)
});
and remove the key in the child (ListItem) component
ListItem.js
<li
/* Remove this
key={id}
*/
className='list__item'>
OR
Get rid of the empty brackets (<> </>) and reference the child's component directly.
let elements=data.map(item => {
return (<ListItem item={item} />)
});
and leave the key attribute in the child component
More on React Fragment. React Official Docs
I am new to react and was trying to use a map function inside jsx to render an array. However nothing gets rendered inside the loop .
I am passing data to my child component like this:
{showMaterialConfirmModal && (
<MaterialModalConfirm
closeModal={setshowMaterialConfirmModal}
orderList={orderListE}
itemList={itemListE}
errorList={errorListE}
title="Success"
/>
)}
and inside the child component I am calling the map function like this:
<Card>
<GridContainer>
<GridItem xs={12}>Design Successful for: 0</GridItem>
<h5>Order:{props.orderList[0]}</h5>
{props.orderList.map((order, i) => {
<div>
{order}
<h1>Hi</h1>
{/* <GridItem xs={12}>
order/item no {order[i]}/{props.itemList[i]} due to{" "}
{props.errorList[i]}
</GridItem> */}
</div>;
})}
</GridContainer>
</Card>
The data in orderList is coming in the tag however nothing gets printed which is inside the loop.
I have checked various documents to run the map function however I am at a loss as to why nothing is getting printed .
Please help
I think you are missing a return here:
{props.orderList.map((order, i) => {
return (
<div>
{order}
<h1>Hi</h1>
</div>);
})}
or
{props.orderList.map((order, i) => (
<div>
{order}
<h1>Hi</h1>
</div>
))
}
I have an object containing several arrays like:
const Items = {
Deserts: [{name:cookies}, {name:chocolate}],
Fruits: [{name:apple}, {name:orange}]
...
}
I want to render it as:
<title>Deserts</title>
Cookies
Chocolate
<title>Fruits</title>
Apple
Orange
So first I render the type:
return <Grid>
{Object.keys(Items).map(type => {
return <Box key={type}>
{type} // <== this would be the title, Fruits or whatever
{this.createCard(Items[type])}
</Box>
})}
</Grid>
Then I want to add the content of each type:
createCard = (items) => {
return <Box>
{items.forEach(item => {
return <div>{item.name}</div>
})}
</Box>
}
Content is not returned, it works fine if instead of a forEach loop I just add some predefined content.
The forEach method only iterates over all items but does not return anything. Instead, what you want to use is a map.
Also, make sure you wrap your return value when it extends more than one line:
createCard = (items) => {
return (<Box>
{items.map(item => {
return <div>{item.name}</div>
})}
</Box>);
}
If you don't do that it works as if a semicolon was introduced after the first line. So, in reality, your current code is equivalent to:
createCard = (items) => {
return <Box>;
// The code below will never be executed!
{items.forEach(item => {
return <div>{item.name}</div>
})}
</Box>
}
When returning an element you need to wrap it in parentheses, ( ) and I generally use map instead of forEach.
const createCard = items => {
return (
<Box>
{items.map(item => {
return ( <div>{item.name}</div> )
})}
</Box>
)
}
I believe you can also nix the curly braces if the function doesn't need any logic.
const createCard = items => (
<Box>
{items.map(item => {
return ( <div>{item.name}</div> )
})}
</Box>
)
-- Edit --
Now that I'm reading back over your question a much cleaner way to approach this would be to declare the component function outside of your class like
class Grid extends react.Component {
render(){
return (
<Box>
<CreateCard props={ item }/>
</Box
)
}
}
const CreateCard = props => (
<Box>
{props.items.map(item => {
return ( <div>{item.name}</div> )
})}
</Box>
)