Reputation: 646
I have a few components nested inside a larger "controller" component.
The whole demo app is below. There's also a StackBlitz.
import React, { useState } from 'react';
import CodeEditor from './CodeEditor';
import './style.css';
const PostEditor = ({ value, onChange }) => {
return (
<>
{value && (
<>
<CodeEditor value={value} onChange={value => onChange(value)} />
</>
)}
</>
);
};
const Wrapper = ({ post, updatePostProperty }) => {
return (
<>
<h2>Selected post: {post && post.title}</h2>
{post && post.title && (
<PostEditor
value={post.title}
onChange={value => {
console.log('update title->', value);
updatePostProperty(post.id, 'title', value);
}}
/>
)}
{post && post.subTitle && (
<PostEditor
value={post.subTitle}
onChange={value => {
console.log('update subTitle->', value);
updatePostProperty(post.id, 'subTitle', value);
}}
/>
)}
</>
);
};
export default function App() {
const [posts, setPosts] = useState([
{ id: 1, title: 'post no 1', subTitle: 'subtitle no 1' },
{ id: 2, title: 'post no 2', subTitle: 'subtitle no 2' },
{ id: 3, title: 'post no 3', subTitle: 'subtitle no 3' }
]);
const [post, setPost] = useState();
const updatePostProperty = (id, property, value) => {
const newPosts = [...posts];
const index = newPosts.findIndex(post => (post.id === id));
newPosts[index] = {
...newPosts[index],
[property]: value
};
setPosts(newPosts);
};
return (
<div>
<ul>
{posts &&
posts.length > 0 &&
posts.map((post, index) => (
<li
style={{ cursor: 'pointer' }}
onClick={() => {
setPost(post);
}}
>
{post.title} - {post.subTitle}
</li>
))}
</ul>
<Wrapper post={post} updatePostProperty={updatePostProperty} />
</div>
);
}
The App
component hosts the updatePostProperty
that is passed on to the Wrapper
component which uses it when the PostEditor
component triggers onChange
the CodeEditor
which is a wrapper for CodeMirror
.
The issue here is that after you click one of the posts and edit the title and then the subtitle, the title gets reverted to the initial value.
Scenario:
Click on the first post and try to edit the title. Add an !
to the title. You'll see the post on the list gets updated.
After you edit the subtitle by adding a character to it, you'll see the title gets reverted to the previous state (without the !
) in the App
component.
Why is react doing this "revert" update?
Update:
useEffect
before changing the original posts
array.input
element to see if the problem persists. It seems that the issue is fixed with regular input
s.However, I'd love someone's input on why does the issue still persists with the way CodeMirror is wired up.
Upvotes: 0
Views: 269
Reputation: 369
newPosts
instead of posts
=
here newPosts.findIndex(post => (post.id = id));
there suppose to be 2 ==
like newPosts.findIndex(post => (post.id == id));
checkout this code
const updatePostProperty = (id, property, value) => {
const newPosts = [...posts];
const index = newPosts.findIndex(post => (post.id == id));
newPosts[index][property] = value
setPosts(newPosts);
};
Upvotes: 0
Reputation: 1241
Inside updatePostProperty
you're updating the wrong object.
You're updating:
posts[index] = {
...newPosts[index],
[property]: value
};
But you want to update newPosts
instead, so you have to do:
newPosts[index] = {
...newPosts[index],
[property]: value
};
Upvotes: 1