Issues mapping within a map - React Native - arrays

The app I'm making develops the following array format to store user input:
[
{name: Bob,
id: 1,
sports: [{sport: Baseball,
id: 1
},
{sport: Basketball,
id: 2
}]
},
{name: James,
id: 2,
sports: [{sport: Hockey,
id: 3
},
{sport: Soccer,
id: 4
}]
}
]
I am trying to render this to effectively get the following output:
<Text>Bob</Text>
<Text>Baseball</Text>
<Text>Basketball</Text>
<Text>James</Text>
<Text>Hockey</Text>
<Text>Soccer</Text>
I would of thought I could achieve this by mapping within a map eg:
{Array.map((item) => {
return(
<Text>{item.name}</Text>
{item.sports.map((item2) => {
return(
<Text>{item2.sport}</Text>
)
})
)
})}
but can't get anything like this to work. I can console.log the results I want with:
const display = Array.map(item => {
return console.log(item.name, item.sports.map(item2 => {
return item2.sport}))
})
But I guess I don't know how to render this out?

You have a lot of errors in the code or is it a neglect of responders.
const userInput = [
{
name: "Bob",
id: 1,
sports: [
{ sport: "Baseball", id: 1 },
{ sport: "Basketball", id: 2 },
],
},
{
name: "James",
id: 2,
sports: [
{ sport: "Hockey", id: 3 },
{ sport: "Soccer", id: 4 },
],
},
];
{userInput.map((user) => (
<>
<Text>{user.name}</Text>
{user.sports.map((s) => (
<Text>{s.sport}</Text>
))}
</>
))}

Ok so I just found out what I was doing wrong haha. I need to have the content from my first map and the second map function encased in one View. Eg:
const display = Array.map(item => {
return (
<View> <------------------------I didn't have these originally
<View>
<Text>
{item.name}
</Text>
</View>
{item.sports.map(item2 => {
console.log(item2)
return (
<View>
<Text>
{item2.sport}
</Text>
</View>
)
})}
</View> <------------------------I didn't have these originally
)
})

Related

Get data from an array to create dynamically <Text> component react-native

I got array:
const DATA_Section = [
{
id: 0,
text: "Some text1",
},
{
id: 1,
text: "Some text2",
},
{
id: 2,
text: "Some text 3",
},
];
and I want to use text from this array to create dynamic component. Idea is: I can see text[0], I click some button then I can see text[1], something like loop. How can to do it?
You can do this way maybe.
const DATA_Section = [
{
id: 0,
text: "Some text1",
},
{
id: 1,
text: "Some text2",
},
{
id: 2,
text: "Some text 3",
},
];
const Component: FC = () => {
const [initialRenderState, setInitialRenderState] =
useState(DATA_Section[0])
return (
<View>
{intialRenderState.map(item => <Text key={item.id}>{item.text}</Text>)}
<Pressable onPress={()=> setInitialRenderState(prevState => [...prevState, Data_Section[prevState.length]])}>
<Text>Add item</Text>
<Pressable>
</View>
)
}
const DATA_Section = [
{
id: 0,
text: "Some text1",
},
{
id: 1,
text: "Some text2",
},
{
id: 2,
text: "Some text 3",
},
];
const sample = () => {
const [ index, setIndex ] = useState(0);
const handleChangeIndex = () => {
if (index < DATA_Section.length) {
setIndex(index + 1);
}else{
setIndex(0);
}
}
return(
<View style={{flex:1}}>
<TouchableWithoutFeedback onPress={()=>handleChangeIndex()}>
<View style={{width:100, height:50, backgroundColor:'red'}}>
<Text>
{DATA_Section[index].text}
</Text>
</View>
</TouchableWithoutFeedback>
</View>
);
}

Unique ID don't fix "unique key" error when rendering nested lists in React

I can't get rid of the classic React "Each child in the list should have a unique key".
I'm rendering a big array, with items that can have sub items.
To prevent all of this, i created a data structure with unique id for every item.
This is my data:
export const assetListConfig: RolesListItem[] = [
{
id: 1,
title: t('Asset creation'),
name: 'Asset-Create',
type: 'switch',
},
{
id: 2,
title: t('Edit asset info'),
name: 'Asset-Edit',
type: 'switch',
},
{
id: 3,
title: t('Archive'),
name: 'Asset-Archive',
type: 'switch',
},
{
id: 4,
title: t('Delete'),
name: 'Asset-Delete',
type: 'switch',
subLists: [
{
subListWatch: 'Asset-Delete',
items: [
{
id: 5,
title: t('Bulk deletion'),
name: 'Asset-Delete-Bulk',
type: 'switch',
},
],
},
],
},
{
id: 6,
title: t('Resources'),
name: 'Asset-Manage-Resources',
type: 'switch',
},
{
id: 7,
title: t('Enable public'),
name: 'Asset-Set-Public',
type: 'switch',
},
{
id: 8,
title: t('Enable redirect'),
name: 'Asset-Set-Redirect',
type: 'switch',
},
{
id: 9,
title: t('Enable tickets'),
name: 'Asset-Enable-Tickets',
type: 'switch',
},
{
id: 10,
title: t('Edit hierarchy'),
name: 'Asset-Edit-Hierarchy',
type: 'switch',
itemWatch: ['Asset-Edit'],
},
{
id: 11,
title: t('Locations'),
name: 'Asset-Location',
type: 'switch',
},
{
id: 12,
title: t('Manage asset tags'),
name: 'Asset-Manage-Tags',
type: 'switch',
},
{
id: 13,
title: t('Logbook'),
name: 'Asset-Logbook-Read',
type: 'switch',
subLists: [
{
subListWatch: 'Asset-Logbook-Read',
items: [
{
id: 14,
title: t('Comment'),
name: 'Asset-Logbook-Comment',
type: 'switch',
},
{
id: 15,
title: t('Allow export'),
name: 'Asset-Logbook-Export',
type: 'switch',
},
],
},
],
},
{
id: 16,
title: t('Components'),
name: 'Component-Read',
type: 'switch',
subLists: [
{
subListWatch: 'Component-Read',
items: [
{
id: 17,
title: t('Instances'),
name: 'Component-Instance',
type: 'radio',
radioOptions: [
{ label: t('Manage'), value: 'Component-Instance-Manage' },
{
label: t('Delete'),
value: 'Component-Instance-Delete',
inputWatch: 'Component-Instance-Manage',
},
],
},
{
id: 18,
title: t('Models'),
name: 'Component-Model',
type: 'radio',
radioOptions: [
{
label: t('Manage'),
value: 'Component-Model-Manage',
inputWatch: 'Component-Instance-Manage',
},
{
label: t('Delete'),
value: 'Component-Model-Delete',
inputWatch: 'Component-Model-Manage',
},
],
},
],
},
],
},
{
id: 19,
title: t('Workshifts'),
name: 'Asset-Running-Read',
type: 'switch',
subLists: [
{
subListWatch: 'Asset-Running-Read',
items: [
{
id: 20,
title: t('Manage status'),
name: 'Asset-Running-Status-Manage',
type: 'switch',
},
{
id: 21,
title: t('Manage expectations'),
name: 'Asset-Running-Expectation-Manage',
type: 'switch',
},
{
id: 22,
title: t('Manage schedules'),
name: 'Asset-Running-Schedule-Manage',
type: 'switch',
},
],
},
],
},
];
I render lists with .map also for radiogroup options and item sublists.
This is the component in which I get the error:
import shortid from 'shortid'
export const UserRolesList: React.FC<ListItemProps> = ({
listConfig,
userData,
isSubList = false,
}) => {
handleChange ecc ecc...
return (
<RolesListWrapper isSubList={isSubList}>
<ul
className="list--unbulleted display--ib full-width"
>
/* FIRST LIST RENDERING */
**{listConfig.map((listItem, index) => {
const {
name,
title,
type,
radioOptions = [],
selectOptions = [],
id: skillId,
subLists,
} = listItem;**
const visibleOptions = renderVisibleOptions(radioOptions);
return (
<>
{isListItemVisible(listItem) ? (
**<li
className={`pad pad-double--sides shadow--list-item ${
index !== listConfig.length - 1 ? 'push--bottom' : ''
}`}
key={skillId}
style={
isSubList
? {
padding: '0',
boxShadow: 'none',
}
: {
width: 'auto',
minWidth: '350px',
}
}
>**
<div className="full-width flex--space-items">
<div
className="pad flex--align-center"
style={{
paddingLeft: isSubList ? 'var(--base-space)' : '',
flexBasis: '160px',
}}
>
{title}
</div>
{type === 'switch' ? (
<div className="pad flex--align-center">
<Switch
onColor="#21b151"
offColor="#e02f2f"
checked={findActiveSkill(name)}
onChange={() => handleSkillChange(name)}
disabled={isAddingSkill || isRemovingSkill}
/>
</div>
) : null}
{type === 'radio' ? (
**<div
className="flex-item--fill"
style={{
display: 'grid',
gridTemplateColumns: 'repeat(3,1fr)',
}}
>
/* SECOND LIST RENDERING */
{visibleOptions.map((opt) => (
<div
className="flex--align-center"
style={{
gridColumn: opt.value.includes('Delete')
? '3'
: undefined,
}}
key={shortid.generate()}
>**
<input
type="checkbox"
className="qtrack-form-input__selection"
value={opt.value}
id={opt.value}
checked={findActiveSkill(opt.value)}
onChange={(e) =>
handleSkillChange(e.target.value)
}
disabled={isAddingSkill || isRemovingSkill}
/>
<label
style={{ margin: '5px 0' }}
htmlFor={opt.value}
>
{opt.label}
</label>
</div>
))}
</div>
) : null}
{type === 'select' ? (
<div style={{ margin: '0', minWidth: '220px' }}>
<SimpleSelect
selectOptions={selectOptions}
value={selectOptions.find((opt) =>
skills.includes(opt.value),
)}
isMulti={false}
isClearable
errors={undefined}
onChange={(e: string) => handleSelectChange(e, name)}
name="roles-select"
isDisabled={isAddingSkill || isRemovingSkill}
/>
</div>
) : null}
</div>
{subLists ? (
<SubListHandler subLists={subLists} userData={userData} />
) : null}
</li>
) : null}
</>
);
})}
</ul>
</RolesListWrapper>
);
};
And this is the component in which I render the sublists:
export const SubListHandler: React.FC<{
subLists: RolesList[];
userData: UserData;
}> = ({ subLists, userData }) => (
<>
/* THIRD AND LAST LIST RENDER */
{subLists.map((list) => {
const { subListWatch, items: subItems } = list;
const isSubListVisible = userData.skills.includes(subListWatch);
**const subListId = shortid.generate();**
return (
<div key={subListId}>
{isSubListVisible ? (
**<div>**
{list.title ? (
<div className="txt--bold pad--left push--top">
{list.title}
</div>
) : null}
<div className="push--ends pad--left">
<UserRolesList
listConfig={subItems}
userData={userData}
isSubList
/>
</div>
</div>
) : null}
</>
);
})}
</>
);
As you can see, I'm using unique IDs for all the three map methods in my component.
This is confirmed when I log the IDs I used in the console. They're all different.
I don't know what I'm doing wrong or if I'm messing something with the conditional rendering or nested components
I tried to highlight when the list rendering happens in the code.
This seems pretty straighforward to me as I have unique ids for every list child, but it always throws me an error.
Let me know if you find something wrong with my code.
Thanks a lot!
You need to use the unique id in the 'key' prop of the list items. ie. -
const todoItems = todos.map((todo) =>
<li key={todo.id}>
{todo.text}
</li>
);

React component only rendering one item in my object

So I have a react component set up to map through all the items in my array to display them on the page. I'm importing my component onto my homepage and passing the object as a prop from the imported component. However, when I load the page, only one item from the object is being rendered. I'm not entirely sure if I'm passing my object correctly. Any help would be appreciated! Code is below.
This is my Modal component. I'm mapping through the listGroupArray that has a spread operator with my data that is being passed from the home page.
export default function ModalButton({ setData, title, arrayData, dataTitle }) {
const [show, setShow] = useState(false);
const [button, setButton] = useState("Choose...")
const handleClose = () => setShow(false);
const handleShow = () => setShow(true);
const listGroupArray = [{...arrayData}]
const changeButton = e => setButton(e)
return (
<>
<h5 className="inputFont text-center">{title}</h5>
<Button style={{ backgroundColor: "black", opacity: "1", color: "white", borderColor: "red" }} variant="primary" className="w-100 mb-4 inputFont" onClick={handleShow}>
{button}
</Button>
<Modal show={show} onHide={handleClose}>
<Modal.Header closeButton className="modal-bg inputFont">
{dataTitle}
</Modal.Header>
<Modal.Body className="modal-bg">
<ListGroup>
{listGroupArray.map(item => (
<ListGroup.Item key={item.id} className="modal-bg">
<Button
style={{
backgroundColor: "black",
opacity: ".8",
color: "white",
borderColor: "red",
}}
className="inputFont w-100"
name={item.name}
value={item.value}
onClick={(e) => {
setData(item.value);
changeButton(item.name);
handleClose();
}}
>
{item.name}
</Button>
</ListGroup.Item>
))}
</ListGroup>
</Modal.Body>
</Modal>
</>
);
}
This is my homepage where I'm passing the array data as an object. I'm pretty sure this is where I'm going wrong. When I load the page, the component should render all the data in the object, however it's only rendering the last data, Classics.
<Modal title="Genre"
dataTitle="Pick A Genre"
setData={setGenrelist}
arrayData={
{
id: 1,
name: "Action and Adventure",
value: "10673,10702,11804,11828,1192487,1365,1568,2125,2653,43040,43048,4344,46576,7442,75418,76501,77232,788212,801362,899,9584"
},
{
id: 2,
name: "Musicals",
value: "13335,13573,32392,52852,55774,59433,84488,88635"
},
{
id: 3,
name: "Sci-Fi",
value: "1492,108533,11014,1372,1568,1694,2595,2729,3327,3916,47147,4734,49110,50232,52780,52849,5903,6000,6926,852491"
},
{
id: 4,
name: "Fantasy",
value: "9744"
},
{ id: 5,
name: "Thrillers",
value: "10306,10499,10504,10719,11014,11140,1138506,1321,1774,3269,43048,46588,5505,58798,65558,6867,75390,78507,799,852488,8933,98911,9147,972"
},
{
id: 6,
name: "Anime",
value: "10695,11146,2653,2729,3063,413820,452,6721,9302,7424"
},
{
id: 7,
name: "Children and Family",
value: "10056,27480,27950,28034,28083,28233,48586,5455,561,6218,6796,6962,78120,89513,783"
},
{
id: 8,
name: "Comedies",
value: "1009,10256,10375,105,10778,11559,11755,1208951,1333288,1402,1747,17648,2030,2700,31694,3300,34157,3519,3996,4058,4195,43040,4426,4906,52104,52140,52847,5286,5475,5610,56174,58905,59169,61132,61330,6197,63092,63115,6548,711366,7120,72407,7539,77599,77907,78163,78655,79871,7992,852492,869,89585,9302,9434,9702,9736"
},
{
id: 9,
name: "Documentaries",
value: "10005,10105,10599,1159,15456,180,2595,2616,2760,28269,3652,3675,4006,4720,48768,49110,49547,50232,5161,5349,55087,56178,58710,60026,6839,7018,72384,77245,852494,90361,9875"
},
{
id: 10,
name: "Dramas",
value: "11,11075,11714,1208954,1255,12995,13158,2150,25955,26009,2696,2748,2757,2893,29809,3179,31901,34204,3653,3682,384,3916,3947,4282,4425,452,4961,500,5012,52148,52904,56169,58755,58796,59064,6206,62235,6616,6763,68699,6889,711367,71591,71591,72354,7243,7539,75459,76507,78628,852493,89804,9299,9847,9873,5763"
},
{
id: 11,
name: "Sports",
value: "180,25788,4370,5286,7243,9327"
},
{
id: 12,
name: "Horror",
value: "10695,10944,1694,42023,45028,48303,61546,75405,75804,75930,8195,83059,8711,89585"
},
{
id: 13,
name: "Romance",
value: "29281,36103,502675"
},
{
id: 14,
name: "Classics",
value: "10032,11093,13158,29809,2994,31273,31574,31694,32392,46553,46560,46576,46588,47147,47465,48303,48586,48744,76186"
}
}
/>
screenshot of the homepage
This image shows the component only rendering one data item which is Classics. Any advice on how to get all data rendered would be greatly appreciated! Thanks!
The error is in how you referenced the arrayData and the problematic curly brackets you used on an array. In your JSX code, you have a syntax error, you are supposed to enclose arrays in curly brackets, or better still just separate them to their own variable.
Your JSX should then look something like this:
function JSX(props) {
const arrayData = [
{
id: 1,
name: "Action and Adventure",
value:
"10673,10702,11804,11828,1192487,1365,1568,2125,2653,43040,43048,4344,46576,7442,75418,76501,77232,788212,801362,899,9584",
},
{
id: 2,
name: "Musicals",
value: "13335,13573,32392,52852,55774,59433,84488,88635",
},
{
id: 3,
name: "Sci-Fi",
value:
"1492,108533,11014,1372,1568,1694,2595,2729,3327,3916,47147,4734,49110,50232,52780,52849,5903,6000,6926,852491",
},
{
id: 4,
name: "Fantasy",
value: "9744",
},
{
id: 5,
name: "Thrillers",
value:
"10306,10499,10504,10719,11014,11140,1138506,1321,1774,3269,43048,46588,5505,58798,65558,6867,75390,78507,799,852488,8933,98911,9147,972",
},
{
id: 6,
name: "Anime",
value: "10695,11146,2653,2729,3063,413820,452,6721,9302,7424",
},
{
id: 7,
name: "Children and Family",
value:
"10056,27480,27950,28034,28083,28233,48586,5455,561,6218,6796,6962,78120,89513,783",
},
{
id: 8,
name: "Comedies",
value:
"1009,10256,10375,105,10778,11559,11755,1208951,1333288,1402,1747,17648,2030,2700,31694,3300,34157,3519,3996,4058,4195,43040,4426,4906,52104,52140,52847,5286,5475,5610,56174,58905,59169,61132,61330,6197,63092,63115,6548,711366,7120,72407,7539,77599,77907,78163,78655,79871,7992,852492,869,89585,9302,9434,9702,9736",
},
{
id: 9,
name: "Documentaries",
value:
"10005,10105,10599,1159,15456,180,2595,2616,2760,28269,3652,3675,4006,4720,48768,49110,49547,50232,5161,5349,55087,56178,58710,60026,6839,7018,72384,77245,852494,90361,9875",
},
{
id: 10,
name: "Dramas",
value:
"11,11075,11714,1208954,1255,12995,13158,2150,25955,26009,2696,2748,2757,2893,29809,3179,31901,34204,3653,3682,384,3916,3947,4282,4425,452,4961,500,5012,52148,52904,56169,58755,58796,59064,6206,62235,6616,6763,68699,6889,711367,71591,71591,72354,7243,7539,75459,76507,78628,852493,89804,9299,9847,9873,5763",
},
{
id: 11,
name: "Sports",
value: "180,25788,4370,5286,7243,9327",
},
{
id: 12,
name: "Horror",
value:
"10695,10944,1694,42023,45028,48303,61546,75405,75804,75930,8195,83059,8711,89585",
},
{
id: 13,
name: "Romance",
value: "29281,36103,502675",
},
{
id: 14,
name: "Classics",
value:
"10032,11093,13158,29809,2994,31273,31574,31694,32392,46553,46560,46576,46588,47147,47465,48303,48586,48744,76186",
},
];
return (
<Modal
title="Genre"
dataTitle="Pick A Genre"
setData={(data) => console.log(data)}
arrayData={arrayData}
/>
);
}
The next bug you had was in using the spread operator. While arrays are technically objects in JavaScript they can't be spread with curly braces. This [{...arrayData}] is syntactically incorrect. Instead it should be [...arrayData]. With these in place, your code should run correctly.
I made a sandbox of your code in a working state for reference, check it out here:
https://codesandbox.io/s/young-snowflake-efqwk?file=/src/ModalButton.js:877-883

Minimizing un-necessary re-renders in a large list React component tree

I am creating a large list with this accordion on React Native. The problem I face is the re-renders that happening in the renderItem function. When the input changes in the Product component whole component tree is re-rendered. Is there way to stop re-rendering the whole component tree for input changes on the product component with using React.memo or React.useMemo ?
const categories = [
{ id: 1, name: 'Category A' },
{ id: 2, name: 'Category B' },
{ id: 3, name: 'Category B' },
]
const products = [
{ id: 1, name: 'Product A', category: 1 },
{ id: 2, name: 'Product B', category: 1 },
{ id: 3, name: 'Product C', category: 2 },
{ id: 4, name: 'Product D', category: 2 },
{ id: 5, name: 'Product E', category: 3 },
]
const handleChange = (product, quantity) => {
console.log('handle change event fired');
};
const renderHeader = (category) => {
return (
<View>
<Text>{category.name}</Text>
</View>
);
};
const renderContent = (category) => {
const categoryProducts = products.filter(product => product.category_id === category.id);
const renderItem = (product) => {
return (
<Product
key={product.id}
product={product}
handleChange={handleChange}
/>
);
};
return (
<View>
{
categoryProducts.map(product => {
return (renderItem(product));
})
}
</View>
);
};
return (
<ScrollView>
<Accordion
sections={categories}
renderHeader={renderHeader}
renderContent={renderContent}
/>
</ScrollView>
);
The Product Compoenent
<View>
<Input
size="small"
keyboardType="number-pad"
onChangeText={(changedQuantity) => {
handleChange( product, changedQuantity);
}}
value={quantity}
/>
</View>

Ant design 4 table loading not working properly

Im using my react project for ant design 4, i added table loading for loading, I have some conflict added loaded not working, anyone know how to fix that issue?
Thanks
code here
Here the stackblitz
const columns = [
{
title: "Name",
dataIndex: "name",
key: "name",
render: text => {text}
},
{
title: "Age",
dataIndex: "age",
key: "age"
},
{
title: "Address",
dataIndex: "address",
key: "address"
},
{
title: "Tags",
key: "tags",
dataIndex: "tags",
render: tags => (
<span>
{tags.map(tag => {
let color = tag.length > 5 ? "geekblue" : "green";
if (tag === "loser") {
color = "volcano";
}
return (
<Tag color={color} key={tag}>
{tag.toUpperCase()}
</Tag>
);
})}
</span>
)
},
{
title: "Action",
key: "action",
render: (text, record) => (
<span>
Invite {record.name}
<Divider type="vertical" />
Delete
</span>
)
}
];
class App extends React.Component {
state = {
data: [],
pagination: {
current: 1,
pageSize: 10
},
loading: true
};
componentDidMount() {
setTimeout(() => {
this.setState({ loading: false });
}, 1000);
}
render() {
const data = [
{
key: "1",
name: "John Brown",
age: 32,
address: "New York No. 1 Lake Park",
tags: ["nice", "developer"]
},
{
key: "2",
name: "Jim Green",
age: 42,
address: "London No. 1 Lake Park",
tags: ["loser"]
},
{
key: "3",
name: "Joe Black",
age: 32,
address: "Sidney No. 1 Lake Park",
tags: ["cool", "teacher"]
}
];
return (
<Table
columns={columns}
dataSource={data}
loading={this.state.loading}
onChange={this.handleTableChange}
/>
);
}
}
ReactDOM.render(<App />, document.getElementById("container"));

Resources