My Vue application uses server-side rendering. When the app has loaded and hydrated, I'd like to detect a condition on the client and then commit a mutation.
If I touch the state before mounting the app, this warning is printed - as expected:
[Vue warn]: The client-side rendered virtual DOM tree is not matching
server-rendered content. This is likely caused by incorrect HTML
markup, for example nesting block-level elements inside <p>, or
missing <tbody>. Bailing hydration and performing full client-side
render.
I thought I'd find a hook that would be called right after the hydration is done.
I tried committing the mutation in the mounted hook of the main component. I also tried doing it after app.$mount(...), and with Vue.nextTick(). All of these were too early: in each of these cases, I get the above warning.
I found two workarounds:
adding a mounted hook in the child component that will render differently with the modified state. That hook is called after the parent hook. Okay for now, since I only need to use it one place. But will get dirty when I need it in two different components.
using an obscure setTimeout(). Breaks easily, since I found no easy way to check whether the hydration is complete, so I can't poll. (The data-server-rendered attribute is removed when hydration begins.)
Any ideas how this could be solved properly?
Related
I'm currently migration a Vue 2 application to Vue 3, and for some reason I'm suddenly getting this warning a lot:
[Vue warn]: Computed property "actions" is already defined in Props.
This happens in a bunch of different components, with a bunch of different properties. If I use the Vue devtools to inspect some components, it looks that a lot of components suddenly have computed properties that are not part of that component, but rather are defined on the parent or grandparent. Somehow all computed properties are passed to child components automatically.
I have no idea what's causing this, and I can't find anything about it in the docs. Also it seems that the warning doesn't always trigger (for example after refreshing they might be gone), so I'm thinking if it's some sort of weird bug.
Btw it doesn't seem to break anything so far.
Thanks in advance!
(Ps. I'm using Vite)
The reason I didn't include any code in my question was because the warning seemed to trigger on many different places / components, and also it seemed to not always trigger, so it was hard to find out what the relevant code was.
I've found that it's an issue with Vue devtools however. When I disable the devtools, I'm not getting the warning. Also noticed that the devtools was slowing down rendering time, not sure if that's related to this issue.
I understand that we need to cleanup our components in React to prevent memory leaks (Maybe other reasons as well). I also understand how to use comonentWillUnmount (don't use anymore), and useEffect hook. However my question is what, and why (really why) do we clean up our components. I'd like a detailed answer please as I am having issues understanding this concept.
You usually don't need to at all.
For most components, simply changing state and then not rendering them will unmount them with no mess.
However, if you do anything that wont be cleaned up, you have to clean it up yourself. This means things that are outside the standard React lifecycle:
Event listeners need be un-bound (i.e. listening for onScroll of window to do something fancy when you scroll the page)
Unsubscribe from data subscriptions that were opened when that component was instantiated. (i.e. Listening for new chat room messages on an open web socket)
Cancel a timeout or interval that is no longer needed. (i.e. update a clock once per second)
This is not an exhaustive list, but the idea is that if you do anything in the lifecycle of your component that is not rendering components with some props, you should probably undo that when the component is unmounted.
Make the most of the components as dump components. display what ever the data provided as props. Make the parent componets responsible for the data fetching. This will make the components more simpler and highly readable. Otherwise no of lines of codes within the components will increase and become less readable.a less readable components is hard to understand for other developers , hard to debugg . Make unsubscribtions on unmounting the components
I'm running into a strange issue with React Router.
I keep getting the warning "Can't call setState (or forceUpdate) on an unmounted component..." even though I can prove that the component in question is hitting its componentDidMount lifecycle method.
I'm perfectly fine with ignoring warnings. The thing is, the app isn't working properly because of this.
Current state of my flailing about:
https://github.com/tomizechsterson/chargen-ui
After starting the app, if you click on the 'AD&D 2nd Edition' link, you can select entries in the table just fine. It's after you navigate away (to either 'Home' or 'D&D 3.5') and back that you can no longer select entries and the warning pops up in the console.
I've tried going through the React Router docs, but wasn't able to figure out what I needed to know to solve this.
Please suggest.
Turns out that converting a lower-level component to a functional component in my hierarchy avoids this issue. Not sure why, but it's removed my roadblock, so there it is
I am hearing the term "mount" too many times while learning ReactJS. And there seem to be lifecycle methods and errors regarding this term. What exactly does React mean by mounting?
Examples: componentDidMount() and componentWillMount()
The main job of React is to figure out how to modify the DOM to match what the components want to be rendered on the screen.
React does so by "mounting" (adding nodes to the DOM), "unmounting" (removing them from the DOM), and "updating" (making changes to nodes already in the DOM).
How a React node is represented as a DOM node and where and when it appears in the DOM tree is managed by the top-level API. To get a better idea about what's going on, look at the most simple example possible:
// JSX version: let foo = <FooComponent />;
let foo = React.createElement(FooComponent);
So what is foo and what can you do with it? foo, at the moment, is a plain JavaScript object that looks roughly like this (simplified):
{
type: FooComponent,
props: {}
}
It's currently not anywhere on the page, i.e. it is not a DOM element, doesn't exist anywhere in the DOM tree and, aside from being React element node, has no other meaningful representation in the document. It just tells React what needs to be on the screen if this React element gets rendered. It is not "mounted" yet.
You can tell React to "mount" it into a DOM container by calling:
ReactDOM.render(foo, domContainer);
This tells React it's time to show foo on the page. React will create an instance of the FooComponent class and call its render method. Let's say it renders a <div />, in that case React will create a div DOM node for it, and insert it into the DOM container.
This process of creating instances and DOM nodes corresponding to React components, and inserting them into the DOM, is called mounting.
Note that normally you'd only call ReactDOM.render() to mount the root component(s). You don't need to manually "mount" the child components. Every time a parent component calls setState(), and its render method says a particular child should be rendered for the first time, React will automatically "mount" this child into its parent.
React is an isomorphic/universal framework. That means that there is a virtual representation of the UI component tree, and that is separate from the actual rendering that it outputs in the browser. From the documentation:
React is so fast because it never talks to the DOM directly. React maintains a fast in-memory representation of the DOM.
However, that in-memory representation is not tied directly to the DOM in the browser (even though it is called Virtual DOM, which is an unfortunate and confusing name for an universal apps framework), and it is just a DOM-like data-structure that represents all the UI components hierarchy and additional meta-data. Virtual DOM is just an implementation detail.
"We think the true foundations of React are simply ideas of components and elements: being able to describe what you want to render in a declarative way. These are the pieces shared by all of these different packages. The parts of React specific to certain rendering targets aren't usually what we think of when we think of React." - React js Blog
So, the conclusion is that React is Rendering agnostic, which means that it doesn't care about what is the final output. It can be a DOM Tree in the browser, it can be XML, Native components or JSON.
"As we look at packages like react-native, react-art, react-canvas, and react-three, it's become clear that the beauty and essence of React has nothing to do with browsers or the DOM." - React js Blog
Now, that you know how React works, it is easy to answer your question :)
Mounting is the process of outputting the virtual representation of a component into the final UI representation (e.g. DOM or Native Components).
In a browser that would mean outputting a React Element into an actual DOM element (e.g. an HTML div or li element) in the DOM tree. In a native application that would mean outputting a React element into a native component. You can also write your own renderer and output React components into JSON or XML or even XAML if you have the courage.
So, mounting/unmounting handlers are critical to a React application, because you can only be sure a component is output/rendered when it is mounted. However, the componentDidMount handler is invoked only when rendering to an actual UI representation (DOM or Native Components) but not if you are rendering to an HTML string on the server using renderToString, which makes sense, since the component is not actually mounted until it reaches the browser and executes in it.
And, yes, Mounting is also an unfortunate/confusing name, if you ask me. IMHO componentDidRender and componentWillRender would be much better names.
Mounting refers to the component in React (created DOM nodes) being attached to some part of the document. That's it!
Ignoring React you can think of these two native functions as mounting:
replaceChild
appendChild
Which are likely the most common functions React uses to mount internally.
Think of:
componentWillMount === before-mount
And:
componentDidMount === after-mount
https://facebook.github.io/react/docs/tutorial.html
Here, componentDidMount is a method called automatically by React when a component is rendered.
The concept is that you're telling ReactJS, "please take this thing, this comment box or spinning image or whatever it is I want on the browser page, and go ahead and actually put it on the browser page. When that's done, call my function that I've bound to componentDidMount so I can proceed."
componentWillMount is the opposite. It will fire immediately BEFORE your component renders.
See also here
https://facebook.github.io/react/docs/component-specs.html
Finally, the "mount" term seems to be unique to react.js. I don't think it is a general javascript concept, or even a general browser concept.
Mounting refers to the initial page loading when your React component is first rendered. From React documentation for Mounting: componentDidMount:
Invoked once, only on the client (not on the server), immediately after the initial rendering occurs. At this point in the lifecycle, the component has a DOM representation which you can access via React.findDOMNode(this).
You can contrast this with componentDidUpdate function, which is called everytime that React renders (except for the initial mount).
The main goal of React js is to create reusable components. Here, components are the individual parts of a webpage. For example, in a webpage the header is a component, the footer is a component, a toast notification is a component and etc. The term "mount" tells us that these components are loaded or rendered in the DOM. These are many top-level APIs and methods dealing with this.
To make it simple, mounted means the component has been loaded to the DOM and unmounted means the components has been removed from the DOM.
I know I can pass props while rendering a component. I'm also aware of the getInitialState method. But the problem is, getInitialState isn't quite helping because my component doesn't know it's initial state. I do. So I want to pass it while I'm rendering it.
Something like this (pseudo-code):
React.render(<Component initialState={...} />);
I know I could use a prop to work as the initial state but this smells like an anti-pattern.
What should I do?
EDIT FOR CLARITY
Imagine I have a CommentList component. By the time I first render it, the initial state corresponds to the snapshot of current comments from my database. As the user includes comments, this list will change, and that's why it should be a state and not props. Now, in order to render the initial snapshot of comments I should pass it to the CommentsList component, because it has no way to know it. My confusion is that the only way I see to pass this information is through a props which seems to be an anti-pattern.
Disclaimer: Newer versions of React handle this on a different way.
Only permanent components might be able to use props in the getInitialState. Props in getInitialState is an anti-pattern if synchronization is your goal. getInitialState is only called when the component is first created so it may raise some bugs because the source of truth is not unique. Check this answer.
Quoting documentation:
Using props, passed down from parent, to generate state in
getInitialState often leads to duplication of "source of truth", i.e.
where the real data is. Whenever possible, compute values on-the-fly
to ensure that they don't get out of sync later on and cause
maintenance trouble
You can still do:
getInitialState: function() {
return {foo: this.props.foo}
}
As they will be the default props for your app. But as long as you are using a prop to set a value that presumably won't change, you can use the same prop inside of the render function.
<span>{this.props.foo}</span>
This props won't be modified, so no problem using it each time the render is called.
Edited answer:
In this case your initial state should not be a prop, should be an ajax call which populates the comment list.
To quote the React docs:
Using props, passed down from parent, to generate state in getInitialState often leads to duplication of "source of truth", i.e. where the real data is. Whenever possible, compute values on-the-fly to ensure that they don't get out of sync later on and cause maintenance trouble
And:
However, it's not an anti-pattern if you make it clear that synchronization's not the goal here
So if your props include a value and an initialValue, then it's clear that the latter is for initialization, and there's no confusion.
See the React docs for code examples.
If you know the state then I would tend to argue that the component you are rendering is not really in control of it. The idea in React is that any particular piece of state lives in only a single location.
After seeing the other answers, and studying a little bit about it, I've come to this conclusion:
If you are rendering React in the client (compiled or not), which is the default approach, you should try to make an extra Ajax call from inside your component to get the initial state. That is, don't use props. It's cleaner and less error prone.
However, if you are rendering in the server (Node.js or ReactJs.NET), there's no reason to make this extra Ajax call for each request.. Besides, it's not SEO friendly. You want the complete page to come as the result of your request (including data). So, as #RandyMorris pointed out, in this case it's ok to use props as the initial state, as long as it's exclusively the initial state. That is, no synchronization.