Reputation: 301
i write example of dynamically adding text with react useHooks.And using useState to nest. But, there is a problem, the setState is not working?
when i click the text,The setState in the component does not take effect(Normally, it is add a class to the currently clicked text and delete the class on other texts), how do i do?
Below is the specific code link:
https://codesandbox.io/s/nifty-sky-z0p9w?file=/src/App.js
Thanks!
Upvotes: 1
Views: 2589
Reputation: 1166
The reason it does not work its because you're accessing the value of activeItem
state inside of a function. accessing state inside of a function is not recommended cause it will always have the initial value even if the state were updated. That's why <TableCel>
does not re-render since it does not know that activeItem state had already change.
I recommend that you only access the state inside of useEffect()
, useCallback()
, useMemo()
and inside of the return
statement of your component.
For Example:
function App() {
const [state, setState] = useState('initial Value')
function someFunction(){
// It's not recommended to access the state inside of this function
// cause the value of the state will always be ('initial Value')
// even if the state were updated
console.log(state)
}
useEffect(()=>{
// It's good if you access the value of the state here
// It will be assured it will always have the updated value
console.log(state)
},[state])
return (
// You can also access the value of the state inside return statement
<>
{console.log(state)}
<SomeComponent props={state}/>
</>
)
}
Solution:
Pass the state of activeItem by using context hook. In this way <TableCel> will really know everytime activeItem state change.
Take a look in this code in sandbox link were I use context hook to solve the problem
https://codesandbox.io/s/quiet-star-zo4ej?file=/src/App.js
Upvotes: 1
Reputation: 5054
The issue in your code is that is this:
const [activeItem, setActiveItem] = useState(null);
You are defining this at App
level. And you are expecting this will work in TableCel
which in another component which has its own state.
Better way would be out your TableCel
component outside from App
and use state there. If you need to use inside App
then pass activeItems
and setActiveItem
as a props as well.
Here is code:
import React, { useState } from "react";
import "./styles.css";
export default function App() {
const [activeItem, setActiveItem] = useState(null);
const TableCel = (props) => {
const { title } = props;
return <div>{title}</div>;
};
const cell = [
{
key: 1,
header: <TableCel id={1} title={"Header"} />,
render: (cvm) => (
<>
<p>--</p>
</>
)
},
{
key: 2,
header: <TableCel id={2} title={"Header"} />,
render: (cvm) => (
<>
<p>--</p>
</>
)
},
{
key: 3,
header: <TableCel id={3} title={"Header"} />,
render: (cvm) => (
<>
<p>--</p>
</>
)
},
{
key: 4,
header: <TableCel id={4} title={"Header"} />,
render: (cvm) => (
<>
<p>--</p>
</>
)
},
{
key: 5,
header: <TableCel id={5} title={"Header"} />,
render: (cvm) => (
<>
<p>--</p>
</>
)
}
];
const [cellList, addCells] = useState(cell);
const [count, setCount] = useState(6);
// console.log(cellList);
const addCell = (value) => {
const _cell = {
key: value,
header: <TableCel title="Header" id={value} />,
render: (cvm) => (
<>
<p>--</p>
</>
)
};
addCells([...cellList, _cell]);
};
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<button
onClick={() => {
setCount(count + 1);
addCell(count + 1);
}}
>
add li
</button>
<div>
{cellList
.filter((cell) => cell.key < 60)
.map((filteredPerson, index) => (
<li
key={index}
onClick={() => {
setActiveItem(filteredPerson.key);
}}
className={filteredPerson.key === activeItem ? "cel-active" : ""}
>
{filteredPerson.header}
</li>
))}
</div>
</div>
);
}
Here is the demo: https://codesandbox.io/s/morning-cookies-8eud6?file=/src/App.js:0-2086
Upvotes: 2