Reputation: 117
I am trying to map the values of userIDs to listUserIds, and then use values of listUserIds as keys in listUser function. But it only show the last value. What did I go wrong?
function Search(props) {
var listUserIds = []
const [userIDs, setUserIDs] = useState([]);
useEffect( async() => {
console.log('useEffect has been called!');
await userService.getUserAll().then(response => {
var listUser = response.data;
listUser.forEach(element => {
setUserIDs([element.id]);
});
})
.finally()
}, []);
Object.values(userIDs).forEach(x => listUserIds.push(x));
listUserIds.forEach(x => console.log(x));
const listUser = listUserIds.map((userId) =>
<div key={userId}>
<ThumbnailAdmin id={userId} ></ThumbnailAdmin>
</div>
)
return (
<div class="col-lg-9 mt-4 mt-lg-0" style={{marginLeft:"200px"}}>
<div class="row" >
<div class="col-md-12">
<div class="user-dashboard-info-box table-responsive mb-0 bg-white p-4 shadow-sm">
{listUser}
</div>
</div>
</div>
</div>
);
}
Upvotes: 1
Views: 77
Reputation: 1837
The reason why it's only storing one single value lies in the following line:
listUser.forEach(element => { setUserIDs([element.id]); });
Your userIDs list expect an array and you are in a loop setting a single item giving a new array (value inside square brackets).
To solve using your own code, just remove the forEach and pass the listUser as the value of the setUserIDs.
setUserIDs(listUser);
If you want to improve a bit more, take a look the following code ignoring that I removed the service call and the ThumbnailAdmin to help other community members when checking your question in the future.
function Search() {
const apiUrl = "https://610d402748beae001747b7ac.mockapi.io/v1/users",
const [userIDs, setUserIDs] = useState([]);
useEffect(() => {
async function loadUserIDs() {
fetch(apiUrl)
.then((response) => response.json())
.then((data) => setUserIDs(data.map((user) => user.id)));
}
loadUserIDs();
}, [setUserIDs]);
const renderIDs = () => {
return userIDs.map((id) => (
<div className='id-container'>
<div className='id-item' id={`item_${id}`}>{id}</div>
</div>
));
};
return (
<div class="col-lg-9 mt-4 mt-lg-0" style={{ marginLeft: "200px" }}>
<div class="row">
<div class="col-md-12">
<div class="user-dashboard-info-box table-responsive mb-0 bg-white p-4 shadow-sm">
{renderIDs()}
</div>
</div>
</div>
</div>
);
}
code review: To prevent racing condition (useEffect and async function) I implemented the async function in a better way. Reference: React Hook Warnings for async function in useEffect: useEffect function must return a cleanup function or nothing
It can also be an arrow function.
(async () => {
fetch(apiUrl)
.then((response) => response.json())
.then((data) => setUserIDs(data.map((user) => user.id)));
})();
just in time: avoid as much as possible to pass empty array as the parameter of the useEffect.
React Explanation on how to useEffect works:
"... If you pass an empty array ([]), the props and state inside the effect will always have their initial values. While passing [] as the second argument is closer to the familiar componentDidMount and componentWillUnmount mental model, there are usually better solutions to avoid re-running effects too often. Also, don’t forget that React defers running useEffect until after the browser has painted, so doing extra work is less of a problem.".
Source: https://reactjs.org/docs/hooks-effect.html
Upvotes: 1
Reputation: 12787
You need to pass an array of id in setUserIDs
:
setUserIDs(listUser.map((element) => element.id));
Upvotes: 0
Reputation: 5912
You can set the values like this. using map you can collect all the ids then you can update the state.
await userService.getUserAll().then(response => {
var listUser = response.data;
let ids = listUser.map(element => element.id);
setUserIDs(ids);
})
Upvotes: 1