-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Do child components need @observer
?
#101
Comments
Could you include the full code listings? |
I was putting a complete example up on fiddle, when I realised I did not include the Now it appears to work fine. |
i'm a little bit confused, is say if i have a container with |
yes, |
So what's the best practice for mobx? Would you recommend to decorate |
exactly. |
Well that clears things up. Thanks |
Michel, is there any performance drawback if you use @observer in a component which doesn't get any observable? Imagine we make all our app components observer by default. Is there any benefit on manually choosing those which are actually using observables? |
The performance of adding If it would be convenient to you or anyone else feel free to file a feature request for a base |
That seems like a nice idea. I actually used something like that, since we don't need state at all we can actually use stateless components syntax. //MobxObserver.jsx
const MobxObserver = mobxReact.observer((props) => <div>{props.children}</div>);
export default MobxObserver; Then in my component import MobxComponent from 'components/MobxObserver';
class MapContainer extends MobxObserver {
///..etc
} |
Interesting, thanks! |
Could you elaborate on that? How is it possible to shallow compare the observable props if they are not immutable? |
if the object is mutable but observable, children don't need to be updated as they are already observing the object. Say you have a Task object t1 which is passed by |
Ok, one thing I'm still not getting is implementation of shouldComponentUpdate of TodoView in this example. If t1 changes some of its observable properties, it is still the same instance of Task. I assume since t1 is observable, TodoView is notified of change and re-renders. Does that mean that TodoView's shouldComponentUpdate is bypassed in this case? Normally it would determine that t1 is the same instance as before and skip the rendering... |
@vladimir-rovensky exactly. It knows that it has to rerender, so the |
Very nice, thank you for explaining. |
Btw, it is explained in more detail here: https://www.mendix.com/tech-blog/making-react-reactive-pursuit-high-performing-easily-maintainable-react-apps/. It explains also how it results in 100% non-wasted renderings. |
I know that's closed but I'm still a little bit confused. When I use observe on parent, parent gets the updated data from observable store and may pass them to the children. Even when children do not have observe wrapping, they should update (new props should be passed down). At least when I modify your fiddle https://jsfiddle.net/mweststrate/wv3yopo0/ and remove observe from TodoView, it still updates itself and updates the count, too. I understand that for performance reasons it is good to decorate children, because they may update without updating the parent, right? So when I removed the observe decorator, I forced the parent to rerender on change (it rerenders anyway because the count, but if the count would not be there, it would not be re-rendered if todo is decorated...?) For example when I have the component to render a list of items that are supposed not to change (like listing of products) and my parent component (still sticking to HoC) just decide what list (different filters, sorting etc.) to display, the list doesn't have to be decorated (but as I see it has no measurable negative effect on performace it it is). Is it right? When I would compute (as observable aggregated data) the list in this HoC the list according to (router paths and query), and pass this computed list to the children (to display this list), they still do not need to be decorated? Or they has to be because they observe the computed value from HoC? I cannot believe that MobX exists because I see it as a dreams come true. I like Redux but sometimes I'm lost in all dispatching, reducing, thunks and normalized store. MobX seems to be so intuitive and straightforward. Thanks a lot for your work. |
Lot of questions, I'll try to answer them with a generic explanation. You can best see Take a look at the following example: class Person {
@observable age = 30
@observable firstName = "Foo"
@observable lastName = "Bar"
@computed /*?*/ get displayName() {
console.log("calculating displayName")
return this.firstName + this.lastName
}
}
var p = new Person();
autorun(() => {
console.dir(p.age + p.displayName)
})
p.firstName = "John"
p.age = 30; Now should However, if That means that if the You can best see this whole mechanism as a function stack (it actually is); when an observable is read it will always be associated with the function on top of the stack. The more often you push another function on top of the stack, the less work each function has to do (less data to track). All variations of The same holds for The only use case for not using A bit elaborate and I hope that helps to answer your question by giving some insight in what happens behind the scenes. Otherwise just let me know :) |
@mweststrate That's excellent answer, thank you! I'm getting into it and I like the approach a lot. |
@mweststrate I think you meant to change the age in the last line of your example to show how the autorun uses the cached latest value of |
Can anyone please provide me an example of using mobx with big 3-rd party component library like ant-design?
As you can see here we have Table and Column that is bound to dataIndex by property name. To make it work we have to recompile whole ant-design project, that have references on more internal https://github.com/react-component components (we have to mark them as observer also). How one can wrap ALL external components without recompilation? |
If the component (using |
Answering myself, yes, an arrow function created inside the parent render method will make the child to re-render every time the parent renders. To avoid that we can create a method or arrow function as class member. |
Adding `@observer` to all React components can have a great positive impact on performance. You can see more info about it in this discussion with an owner of mobx: mobxjs/mobx#101
Adding `@observer` to all React components can have a great positive impact on performance. You can see more info about it in this discussion: mobxjs/mobx#101
Since these components are passed an observable array, they won't re-render automatically when the array's internals update, and instead only re-render when a primitive value updates. This means that their rendering is always a step behind in the simulation. This makes the less pure-componenty, but seems to be the recommended way. See: mobxjs/mobx-state-tree#1060 https://github.com/mobxjs/mobx-react#faq mobxjs/mobx#101 An alternative would be to use `getSnapshot(data)`, but this is claimed to be less efficient. (Untested, and perhaps for our use-case is negligible and the cleaner code would be preferred.)
Pardon me, I am just a little bit confused but I get what should I do to fix this issue. const Main = observer(() => {
const todoStore = useContext(TodoStore)
return (
<div className='page main'>
{/* Note: This component doesn't get updated - unless parent component re-renders */}
<Todo
todoList={todoStore.todos}
onNewTodo={(val) => todoStore.addTodo(val)}
onModifyTodo={(index, val) => todoStore.modifyTodo(index, val)}
onDeleteTodo={(index) => todoStore.removeTodo(index)}
/>
</div>
)
}) This works btwconst Main = observer(() => {
const todoStore = useContext(TodoStore)
return (
<div className='page main'>
<ul
className='todo__list'
>
{todoStore.todos.map((todo, index) => (
<li
className='todo__list__item'
key={index}
>
{todo.task}
</li>
))}
</ul>
</div>
)
}) So, in that type of architecture what are you supposed to do? Or if you're using a UI framework like Semantic where the framework has no knowledge of what state manager you're using? |
Please, refrain from commenting on old and closed issues as only a few people will see that. Open new issue with all necessary details. |
Hello,
I've been experimenting with mobserbables for a few days, and ran into an issue, but I'm not quite sure it's a bug or by design
(I'm new to react as well)
I currently have two components, a container and a child.
The container is passed a store that contains a observable array, and then is passes that array into the child.
A bit like this:
//main.jsx
//container.jsx
//child.jsx
I'm trying to re-render the child when I change that array on the container, so if I push a new element, or a change a current one the child.jsx will re-render to reflect that change.
The problem is the child.jsx does not re-render
However if I add the same loop in the
container.jsx
render()
, it does.//container.jsx
This way the child.jsx will re-render.
Is this by design? I cannot observe an array form a child unless the parent is directly dependent (uses it on it's own
render()
) on it?Thank you.
The text was updated successfully, but these errors were encountered: