I'm having trouble undestanding the exact moment that React updates the DOM.
Note: I'm using styled-components
in the example below.
See this example:
CodeSandbox: https://codesandbox.io/s/elegant-dirac-j6e54
It shows a transition of the max-height
property of a container.
It workws as intended. I just don't know WHY it works.
The code:
Two lists:
shortList
needs 70px
of height longList
needs 124px
of height const shortList = ["Item 1", "Item 2", "Item 3"];
const longList = ["Item 1", "Item 2", "Item 3", "Item 4", "Item 5", "Item 6"];
I have a styled-component
container named ListContainerDIV
that will handle the transition based on props
. The prop name is idealHeight
.
const ListContainerDIV = styled.div`
overflow: hidden;
max-height: ${props => props.idealHeight + "px"};
transition: max-height ease-out .5s;
`;
App Component
function App() {
// STATE TO KEEP LIST AND REF FOR THE CONTAINER DIV ELEMENT
const [list, setList] = useState(shortList);
const containerDiv_Ref = useRef(null);
// FUNCTION TO TOGGLE BETWEEN LISTS FROM BUTTON CLICK
function changeList() {
setList(prevState => {
if (prevState.length === 3) {
return longList;
} else {
return shortList;
}
});
}
// CALCULATING THE IDEALHEIGHT DURING THE RENDER
let idealHeight = null;
if (list.length === 3) {
idealHeight = 70;
} else if (list.length === 6) {
idealHeight = 124;
}
// RETURNING THE LISTCONTAINER WITH THE `idealHeight` PROP
return (
<React.Fragment>
<button onClick={changeList}>Change List</button>
<ListContainerDIV ref={containerDiv_Ref} idealHeight={idealHeight}>
<ListComponent list={list} />
</ListContainerDIV>
</React.Fragment>
);
}
List Component
This is a simple component to render the <ul>
and the <li>'s
function ListComponent(props) {
const listItems = props.list.map(item => <li key={item}>{item}</li>);
return <ul>{listItems}</ul>;
}
QUESTION
How can this transition be working if I'm setting the max-height
of the component even before the list is rendered? I mean, idealHeight
is being set during the App render. I was thinking that longList
was going to be rendered in a container that already had max-height = 124
? And If that happened, we wouldn't be seeing a transition, right?
What is the order of events that React is running in this situation?
Apparently it updates the <ul>
and the <li>'s
before it updates the div
from the styled-component
container.
An inner component's elements will always be update before the outer component's elements?
UPDATE
Just found these tweets from Dan Abramov about this subject:
With regard to calculating the virtual dom, it starts by rendering the parent components, then renders the child components, then their children, and so on. All of this uses the latest values for state and props, so both App and the various child components know that the list is longer. This virtual dom is just an in-memory description of what you'd like the page to look like.
Once the virtual dom has been calculated, react compares the previous virtual dom with the new one, and finds what has changed. In this case, it finds that there's a new style that needs to be added to the div, and some new li's that need to be inserted to the ul. The exact order these are applied are an implementation detail, but they're applied synchronously and the browser cannot paint in between, so it might as well be simultaneously.
The argument passed to useState, shortList in this case, is the initial state. So when ListContainerDIV is rendered the first time, it's based on the list length being 3, so idealHeight = 70
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.