I am working on my blog and am trying to implement Sanity. I was able to get my posts to show up with the json object returned from query with useState I am trying to populate my React-Modal with the correct contents based on the post I have clicked with its _id or some kind of key. I simplified the code so it wouldn't be too long:
export default function News() {
// Json objects stored in posts
const [posts, setPosts] = useState([]);
// Used to toggle Modal on and off
const [isOpen, setIsOpen] = useState(false);
function toggleModal() {
setIsOpen(!isOpen);
}
return (
<>
{posts.map((posts) => (
<div key={posts._id}>
<h3 className="title" onClick={toggleModal}>
{posts.title}
</h3>
<div">
<a>
<span onClick={toggleModal}>Read More</span>
</a>
</div>
// Clicking on either span or a tag shows the Modal
<Modal
isOpen={isOpen}
onRequestClose={toggleModal}>
// Closes modal
<button className="close-modal" onClick={toggleModal}>
<img
src="assets/img/svg/cancel.svg"
alt="close icon"/>
</button>
// Want to show content based on _id
<h3 className="title">{posts.title}</h3>
<p className="body">{posts.body}</p>
</div>
)
</>
)
}
Whenever I click on a certain post, it always toggles on the first object. Click to see gif demo
Edit: I was able to get it to work based on the answer given
const [state, setState] = useState({ isOpen: false, postId: null });
const openModal = React.useCallback(
(_key) => () => {
setState({ isOpen: true, postId: _key });
},
[]
);
function closeModal() {
setState({ isOpen: false, postId: null });
}
And with Modal tag I added
key={post.id == state.postId}
Now every divs and tags that renders the correct content. However, I'm facing a slight issue. If I click on post[2] and it renders out post[0] content and in a blink of an eye changes to the correct content. Then when I click on post1, it renders and post[2] content and changes to the correct one. It keeps rendering the previous post. It's all in a blink of an eye, but still visible.
I can suggest using react hooks to solve your problem.
You can pass a function to useCallback's return, you can then call your function normally in the render by passing params to it.
See more: https://reactjs.org/docs/hooks-reference.html#usecallback
import * as React from 'react';
export default function News() {
// Json objects stored in posts
const [posts, setPosts] = useState([]);
// Used to toggle Modal on and off
const [isOpen, setIsOpen] = useState(false);
// React.useCallback.
const toggleModal = React.useCallback((id) => () => {
setIsOpen(!isOpen);
console.log(`Post id: ${id}`);
}, []);
return (
<>
{posts.map((post) => (
<div key={post._id}>
<h3 className="title" onClick={toggleModal(post._id)}>
{post.title}
</h3>
<div">
<a>
<span onClick={toggleModal(post._id)}>Read More</span>
</a>
</div>
// Clicking on either span or a tag shows the Modal
<Modal
isOpen={isOpen}
onRequestClose={toggleModal(post._id)}>
// Closes modal
<button className="close-modal" onClick={toggleModal(post._id)}>
<img
src="assets/img/svg/cancel.svg"
alt="close icon"/>
</button>
// Want to show content based on _id
<h3 className="title">{post.title}</h3>
<p className="body">{post.body}</p>
</div>
)
</>
)
}