I'm new to react. I've read through react documentation. I've no idea why it is not working. So, I e up here.
I'm trying to create pagination in react. Below is my table
ponent.
const Table = (props) => {
const { description, itemCount, tableHeaders, items } = props;
const pageSize = 5;
const [currentPage, setCurrentPage] = useState(1);
function handlePageChange(page) {
setCurrentPage(page);
}
const registerations = paginate(items, currentPage, pageSize);
// HERE: registerations data is correct and then I pass it to TableBody ponent.
return (
<React.Fragment>
<TableDescription description={description} count={itemCount} />
<div className="bg-white block w-full md:table">
<TableHeader items={tableHeaders} />
<TableBody items={registerations} />
</div>
{/* Footer & Pagination */}
<div className="bg-white block flex px-6 py-4 justify-between rounded-bl-lg rounded-br-lg">
<div className="sm:flex-1 sm:flex sm:items-center sm:justify-between">
<Pagination
itemsCount={items.length}
pageSize={pageSize}
currentPage={currentPage}
onPageChange={handlePageChange}
/>
</div>
</div>
{/* end Footer & Pagination */}
</React.Fragment>
);
and that registerations array is received by TableBody ponent. The problem here in TableBody ponent is that I can't set props value to state using useState hook.
const { items: passedItems } = props;
console.log(passedItems); // ok -> I got what I passed.
const [items, setItems] = useState(passedItems);
console.log(items); // not ok -> items is previously passed items.
How can I make it right? Thank You.
I'm new to react. I've read through react documentation. I've no idea why it is not working. So, I e up here.
I'm trying to create pagination in react. Below is my table
ponent.
const Table = (props) => {
const { description, itemCount, tableHeaders, items } = props;
const pageSize = 5;
const [currentPage, setCurrentPage] = useState(1);
function handlePageChange(page) {
setCurrentPage(page);
}
const registerations = paginate(items, currentPage, pageSize);
// HERE: registerations data is correct and then I pass it to TableBody ponent.
return (
<React.Fragment>
<TableDescription description={description} count={itemCount} />
<div className="bg-white block w-full md:table">
<TableHeader items={tableHeaders} />
<TableBody items={registerations} />
</div>
{/* Footer & Pagination */}
<div className="bg-white block flex px-6 py-4 justify-between rounded-bl-lg rounded-br-lg">
<div className="sm:flex-1 sm:flex sm:items-center sm:justify-between">
<Pagination
itemsCount={items.length}
pageSize={pageSize}
currentPage={currentPage}
onPageChange={handlePageChange}
/>
</div>
</div>
{/* end Footer & Pagination */}
</React.Fragment>
);
and that registerations array is received by TableBody ponent. The problem here in TableBody ponent is that I can't set props value to state using useState hook.
const { items: passedItems } = props;
console.log(passedItems); // ok -> I got what I passed.
const [items, setItems] = useState(passedItems);
console.log(items); // not ok -> items is previously passed items.
How can I make it right? Thank You.
Share edited Jun 6, 2020 at 16:19 khukho asked Jun 6, 2020 at 15:46 khukhokhukho 4768 silver badges23 bronze badges 2- 1 Why do you need to keep them in the state? This is how state's supposed to behave - not reinitialize on every render – Łukasz Karczewski Commented Jun 6, 2020 at 15:52
- Because I need to keep track of which registerations has opened view-more btn. In my UI, I have view more button on every registeration. So, if I click one of those buttons, I've set { popupVisivility = true } into that registeration object using setItems(). And then table is re-rendered and popup is shown. Is there another way around or other right way to get that achievement? – khukho Commented Jun 6, 2020 at 16:11
3 Answers
Reset to default 4I you want this to work in it's current form:
const { items: passedItems } = props;
console.log(passedItems); // ok -> I got what I passed.
const [items, setItems] = useState([]);
console.log(items); // not ok -> items is previously passed items.
useEffect(() => {
setItems(passedItems)
}, [passedItems])
While use useState hooks you should understand why we need useEffect, so in class based ponents you had the privilege to use callback function in this.setState which will give you the current updated value
this.setState(() => {
name: 'john'
}, () => console.log(this.state.name)) // you will get the immediate updated value
So when you e to functional ponent
const [name, setName] = useState(props.name)
console.log(name) // won't get the updated value
for to get the updated value you can use React.useEffect hook which will trigger whenever array deps as the second argument got changed.
useEffect(() => {
// logic based on the new value
}, [name]) // so whenever the name value changes it will update and call this useEffect
the useEffect can be called in three ways
First One
Without passing an array of deps
useEffect(() => {}) // this will call everytime
Second One
Passing empty array
useEffect(() => {}, []) // passing empty array,it will call one time like the ponentDidMount of class based ponent
Third One
Passing array deps (dependencies)
useEffect(() => {
} , [name, count]) // whenever there is an update of name and count value it will call this useEffect
So in your case you can do the below way
useEffect(() => {
setItems(passedItems)
}, [passedItems]) // whenever passedItems changes this will call and setItems will set the new passedItems
I hope you have clear idea on this.
You need to add a useEffect
to update state
when the props
change.
From the useState
docs:
During subsequent re-renders, the first value returned by useState will always be the most recent state after applying updates.
const TableBody = (props) => {
const { items: passedItems } = props;
// items is set to `passedItems` only on first render
// subsequent renders will still retain the initial value in state
// until `setItems` is called
const [items, setItems] = useState(passedItems);
// add a `useEffect` to update the state when props change
useEffect(() => {
setItems(items)
}, [items])
//
}