I'm trying to figure out how to present data from firestore in a react app, using Ant Design's List.
The List is set up like so:
const data = [
{
title: 'Ant Design Title 1',
},
<List
itemLayout="horizontal"
dataSource={data}
renderItem={item => (
<List.Item>
<List.Item.Meta
avatar={<Avatar src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png" />}
title={{item.title}}
description="Ant Design, a design language for background applications, is refined by Ant UED Team"
/>
</List.Item>
)}
/>
I want to try to put firebase data into the const data - so that the title can be a user.name.
In my component I have:
{loading && <div>Loading ...</div>}
{users.map(user => (
<li key={user.uid}>
I'm trying to convert this to work with Ant Design's list like so:
const data = [
{
//title: `{user.name}`,
title: {user.name},
}
];
<List
itemLayout="horizontal"
dataSource={data}
renderItem={users.map(user => (
// renderItem={item => (
<List.Item>
<List.Item.Meta
// avatar={<Avatar src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png" />}
title={item.title}
description="Ant Design, a design language for background applications, is refined by Ant UED Team"
/>
</List.Item>
))}
/>
When I try this, I get an error that says:
TypeError: renderItem is not a function
Is there an example of how to put data into an Ant Design list using react?
If your firebase users source is an array of objects then just add it directly to dataSource prop.
<List
itemLayout="horizontal"
dataSource={users}
renderItem={item => (
<List.Item>
...
</List.Item>
)}
/>
Related
I'm working on a project using react, next.js, antd.
However, the following error occurred:
Warning: Each child in a list should have a unique "key" prop.
We know that the following error occurs because the list's child element does not have a unique key.
So, I tried to fix the code where the error occurred by using the following methods, but it was not resolved.
const BoardList = () => {
const { boardPosts } = useSelector((state) => state.user);
return (
<section>
<List
itemLayout="vertical"
bordered
size="large"
pagination={{
onChange: (page) => console.log(page), pageSize: 3,
}}
dataSource={boardPosts}
renderItem={(item) => (
<List.Item key={item.id}>
<BoardCard post={item} />
</List.Item>
)}
/>
</section>
)
};
------------------------------
try 0.
<List.Item>
<BoardCard post={item} key={item.id} />
</List.Item>
try 1.
<List.Item key={item.id}>
<BoardCard post={item} />
</List.Item>
try 2.
renderItem={(item, i) => (
<List.Item key={i}>
<BoardCard post={item} />
</List.Item>
try 3.
<List.Item>
<div key={item.id}>
<BoardCard post={item} />
</div>
</List.Item>
try 4.
<div key={item.id}>
<List.Item>
<BoardCard post={item} />
</List.Item>
</div>
So I start to doubt whether the above problem is a problem with the component structure.
The component where the problem occurred consists of the following three components.
// pages/profile
import React from 'react';
import NicknameEditForm from './NicknameEditForm';
import MyScrap from './MyScrap';
import MyBoard from './MyBoard';
const MyInfo = () => {
return (
<section>
<NicknameEditForm /> // A component that changes a member's nickname
<MyScrap /> // Gets the post that has been liked from the POST table.
<MyBoard /> // I get the post I wrote from the POST table.
</section>
)
};
export default MyInfo;
// MyScrap.js
const { likedPosts } = useSelector((state) => state.post);
// MyBoard.js
const { boardPosts } = useSelector((state) => state.post);
Also, MyScrap and MyBoard components receive the following data from the backend and use it.
// likedPosts used in MyScrap component
likedPosts = [{id: 1, title: 'title1',.....}, [...] ...]
// boardPosts used in MyBoard component
boardPosts = [{id: 1, title: 'title1',.....}, [...] ...]
So, I wonder if the following problem occurred because the key values of MyScrap component and MyBoard component overlap due to the following structure on one page or if there is another reason.
Try using rowKey in List component. You can check the example here
const BoardList = () => {
const { boardPosts } = useSelector((state) => state.user);
return (
<section>
<List
itemLayout="vertical"
bordered
size="large"
rowKey={(item) => item.id}
pagination={{
onChange: (page) => console.log(page), pageSize: 3,
}}
dataSource={boardPosts}
renderItem={(item) => (
<List.Item>
<BoardCard post={item} />
</List.Item>
)}
/>
</section>
)
};
I want to when scrolling body add skeleton loading my items in virtualized list
I use the react-viewport-list package
<ViewportList items={dataTable}>
{(item, index) => (
<Row
data={data}
index={index}
setSize={setSize}
windowWidth={windowWidth}
/>
)}
</ViewportList>
What I'm trying to do is get which is the key of the sider the user is using (without ReactDOM and with functional components)
my sample code here:
export default function DrawerSider() {
const history = useHistory();
const [selectedKey, setSelectedKey] = useState("sub1")
const handleSelectKey = function(key, history_string) {
setSelectedKey(key)
history.push(history_string)
console.log(key)
}
return (
<Sider width={200} className="site-layout-background">
<Menu
defaultSelectedKeys={selectedKey}
mode="inline"
style={{ height: "100%", borderRight: 0 }}
>
<Menu.Item
key="sub1"
icon={<HomeOutlined />}
onClick={() => handleSelectKey("sub1","/dashboard/resumo")}
>
Dashboard
</Menu.Item>
<SubMenu key="sub2" icon={<UserOutlined />} title="Usuários">
<Menu.Item
key="1"
icon={<PlusCircleOutlined />}
onClick={() => handleSelectKey("1","/usuarios/novo")}
>
Adicionar usúario
</Menu.Item>
<Menu.Item
key="2"
icon={<TableOutlined />}
onClick={() => handleSelectKey("2","/usuarios/todos")}
>
Todos usúarios
</Menu.Item>
</SubMenu>
<SubMenu key="sub3" icon={<FormOutlined />} title="Formulários">
<Menu.Item
key="3"
icon={<PlusCircleOutlined />}
onClick={() => handleSelectKey("3","/formularios/novo")}
>
Adicionar formulário
</Menu.Item>
</SubMenu>
</SubMenu>
</Menu>
</Sider>
);
}
Obs: I'm using ant design lib
Someone knows how to make it works?
I tried to use a const on click event to set a state of the selected key , but it didn't work
There is no onClick on Menu.Item
only Menu component has onClick or onSelect, both will give you callback of the "clicked" key, the differences is onClick is for any menu item click (including expanding menu) while on select is when you select an actual menu item.
There are 2 ways to get the history string:
1 - use the history string as menuItem key:
the issue would be you cannot have 2 menu item that has same history key
2 - have a map which maps the menu key to history string
see below demo:
https://codesandbox.io/s/inline-menu-antd-4-18-2-forked-bgwyj?file=/index.js
const handleOnSelect = ({ item, key, keyPath, selectedKeys, domEvent }) => {
console.log(item);
console.log(keyPath);
console.log(selectedKeys);
console.log(domEvent);
handleSelectKey(key);
};
...
..
<Menu
onSelect={handleOnSelect}
...
>
...
</Menu>
You need to save the selected key as part of the component's state. You can set the current selected key as part of the onClick.
const selectedKey, setSelectedKey = useState("defaultSelectedKey")
Not sure what the useHistory hook is for but if you need to set that onClick as well as the selectedKey, move it all into one function like so
const handleSelectKey = function(key, history_string) {
setSelectedKey(key)
history.push(history_string)
}
...
onclick={() => handleSelectedKey("3", "/usuarios/novo")}
https://ant.design/components/menu/
EDIT
Based on research into your design library, your onclick and handle select must be at the top level of the menu component. Just copy the syntax that they use in their example code.
https://ant.design/components/menu/
hi i want to ask how to implement material table with lazy loading ? is that possible?
currently im using pagination button but customer want to change to via scroll.or maybe it can implement both.
<MaterialTable
components={{
Cell: props => (
<MTableCell
onDragStart={e => e.preventDefault()}
onContextMenu={e => {
handleEvent(e, props.rowData.tableData.id, props.rowData);
}}
{...props}
/>
),
//current custom pagination via button
Pagination: MTprops => (
<TablePagination
{...MTprops}
count={props.pageCount.total}
page={props.pageCount.current}
rowsPerPage={props.pageCount.limit}
onChangePage={(e, newPageNumber) => handlePageChange(e, newPageNumber, MTprops)}
onChangeRowsPerPage={(e) => {handleRowsPerPageChange(e, MTprops); }}
ActionsComponent={TablePaginationActions}
/>
),
Container: props => <Paper {...props} elevation={0} />
}}
I find code like this to be hard to read:
<Row>
<Column>
{someData.map((value, idx) => (
<Component key={idx}>
<ChildComponent value={value.foo}/>
<ChildComponentTwo value={value.bar}/>
</Component>
)}
</Column>
</Row>
Is there a HOC to replace Array.prototype.map? Say, List that takes a component and generates N components given an array of N items of data mappable to the props of the passed-in component?
declare const data: {value:string}[]
const MyComponentList = List(MyComponent)
<Row>
<Column>
<MyComponentList data={data}/>
</Column>
</Row>
and then Component = ({foo, bar}) => (<>
<ChildComponent value={foo}/>
<ChildComponentTwo value={bar}/>
</>)
Now I don't need map anywhere except I guess in the definition of List. The JSX is much easier to read. But when I search things like "HOC react replace array map JSX" I don't find anything. I suppose List should also inject key={idx} into the "child" components where idx comes from dataArray.map(dataToGoToChild, idx) => <ChildComponent key={idx} {...dataToGoToChild}/>