Reputation: 741
We need to perform some actions related to DOM elements in different parts of the component hierarchy, on window.onresize
and window.onscroll
:
1) Moving elements when resizing to mobile resolution
2) Changing classes and styles when scrolling.
The problem is that the elements are in different levels of the React component hierarchy, i.e. nested in different components. Thus if I understand correctly, I can't use refs
to access the DOM nodes.
I have:
{someCondition ? <FirstComponent/>: <SecondComponent/>}
Whereas someCondition
can change either due to user UI actions, or it could be true from the beginning of the page load.
I've tried using componentDidMount
and componentDidUpdate
on my FirstComponent
, but found that componentDidMount
only fires if someCondition
is true from the beginning, and componentDidUpdate
indeed fires when someCondition
changes, but then the required DOM elements (contained in the component) are not ready at that point, and document.getElementById
fails.
Adding window.requestAnimationFrame
did not help.
I imagine there should be a solid way to do this in React?
Maybe React.findDomNode
?
Thank you.
Upvotes: 3
Views: 1127
Reputation: 39182
What you are describing is the antithesis of React. It is an approach I would expect when using an imperative jQuery/Dojo based framework.
With React, you are developing functional components that know how to convert state into rendered HTML and you need to approach the problem differently.
For your problem, your window.onresize
and window.onscroll
callbacks should not try to manipulate the React DOM elements. Instead it should just update state and let React re-render. Your React components should receive this state and render accordingly.
Here's a simple example where the main app listens to these events and updates its state, which triggers a re-render. The app passes the state as props to the children. The children use the props to conditionally change their css class names. They could easily render different html or inline styles as well.
const Component2 = ({someCondition2}) => {
const className = someCondition2 ? "foo" : "bar";
return <div className={className}>Hello</div>;
};
const Component1 = ({someCondition1, someCondition2}) => {
const className = someCondition1 ? "A" : "B";
return (
<div className={className}>
<Component2 someCondition2={someCondition2} />
</div>
);
};
class App extends React.Component {
state = {
someCondition: false,
someCondition2: true,
};
componentDidMount() {
window.onresize = ev => {
const someCondition = ev.xxx;
// re-render with the new state
this.setState({ someCondition });
};
window.onscroll = ev => {
const someCondition2 = ev.xxx;
this.setState({ someCondition2 });
};
}
render() {
const {someCondition, someCondition2} = this.state;
return (
<Component1
someCondition1={someCondition1}
someCondition2={someCondition2} />
);
}
}
React.render(<App />, document.getElementById("container"));
Upvotes: 4