Let's say I have a large HTML document with numerous React Components embedded in parts of it.
For example:
<body>
<h1 id="react-component-1">...</h1>
<p>Static Content</p>
<h2> id="react-component-2">...</h2>
<img src="static-img" />
<p id="react-component-3">...</h3>
</body>
As you can see, there are static elements in-between my dynamic elements. I'd imagine that this situation is common in web sites that are slowly bringing React in to there toolchain.
Right now my application works like this:
function renderPage(data) {
ReactDOM.render(<Component {...data} />, document.getElementById("react-component-1"));
ReactDOM.render(<Component {...data} />, document.getElementById("react-component-2"));
ReactDOM.render(<Component {...data} />, document.getElementById("react-component-3"));
}
renderPage() is called upon the success of an ajax request. This makes my components update as intended, and it seems pretty performant.
However, it would be much nicer if I had a root React component that handled the state of the application, and pushed down changes to data as props.
I can't make a root component though because not everything on my page is dynamic, I need to preserve the static content in-between the React components.
I would love to be able to do something like this though:
class Root extends React.Component {
constructor(props) {
super(props);
this.data = {...};
}
render() {
ReactDOM.render(<Component {...this.state.data} />, document.getElementById("react-component-1"));
ReactDOM.render(<Component {...this.state.data} />, document.getElementById("react-component-2"));
ReactDOM.render(<Component {...this.state.data} />, document.getElementById("react-component-3"));
}
return false;
}
Is it possible to use React this way? At first I unsure of how it would be possible, because ReactDOM expects an element to render components in to, which would clear out my static content when I render my root component. Now I am thinking I could just do new Root(), but I have yet to test this.
Another option that I just thought of was keeping the renderPage() function and calling it ONCE instead of every time AJAX is loaded. Each component would then listen for a custom event that is fired on the AJAX success, which contains the new data. This seems slower though... And I might as well use Redux for the application state.
You shouldn't use the render method of a React component to call ReactDOM.render the way you do it in your example Root component. The render method of a component can return either a valid React element (for example, <div />) or null and is not supposed to do any mutations, such as modifying the DOM, etc. If a React component needs to do some DOM mutations, it should do it from lifecycle hooks such as ComponentDidMount or ComponentDidUpdate.
To answer you question, it depends whether your static content, can be included in a React component or not.
If you can, which would be ideal, you can refactor your code to have a Root component like so :
class Root extends React.Component {
render() {
return (
<Component data={ this.props.data } />
<p>Static Content</p>
<Component data={ this.props.data } />
<img src="static-img" />
<Component data={ this.props.data } />
);
}
}
and to have one call to ReactDOM.render :
ReactDOM.render(<Root data={ data } />, document.getElementById('my-react-mounting-point'));
If you cannot, that is if you need to have different React render trees, your current approach is fine. If you do this, though, be careful to call ReactDOM.unmountComponentAtNode when you do not need the component anymore, or you might face memory leak issues. This article from React's blog has several nice tips about the precautions to use when having various render trees + a ReactComponentRenderer boilerplate to avoid common pitfalls.
Related
I can define a component like this:
class Welcome extends React.Component {
render() {
return <h1>Hello!</h1>;
}
}
When I want to render this object in the Dom (or rather add it to the virtual DOM) I call
ReactDOM.render(
<Welcome />,
document.getElementById('root')
);
That means that at some point multiple .render() functions are nested inside of each other since we defined return <h1>Hello!</h1>; inside of the .render() function of Welcome.
It also means that I can use the .render() method to render an Object to the DOM and to define a new react object.
This syntax is from the official documentation
Does .render() just render things to the virtual DOM and the nesting is resolved by React internally or is there more behind it?
From Rendering a Component:
(updated to reflect your code)
class Welcome extends React.Component {
render() {
return <h1>Hello!</h1>;
}
}
ReactDOM.render(
<Welcome />,
document.getElementById('root')
);
We call ReactDOM.render() with the <Welcome /> element.
React calls the Welcome component with {} as the props.
Our Welcome component returns a <h1>Hello!</h1> element as the result.
React DOM efficiently updates the DOM to match <h1>Hello</h1>.
It may be beneficial to read up on the React Life Cycle.
To understand render you have to understand how react works internally. To understand this in greater detail I would recoment reading this but here is a quick overview:
Conceptually a react component is a just a function that returns an Object like this:
{
type: 'button',
props: {...}
};
So the render() part of a class component just specifies what part of the component will be returned. The react virtual dom is made up of many of these object nested inside of each other (in props.children). React will start at the top object, turn it into an html node and render it to the dom, then do the same for all of its children etc.
I have a gallery component that takes in an array of components. In each of the child components I am assigning a ref. The reason for this is because within the child component there are many other children components and I am attempting to access some functions on a component that is about 5 component deep. The below code shows the initial setup:
export class Gallery extends React.Component {
render() {
const galleryItems = data.map((item, index) => {
return (
<GalleryItem
ref={React.createRef()}
/>
);
});
return (
<div >
<Gallery
items={heroGalleryItems}
/>
</div>
);
}
}
When the Gallery component renders all the refs in the array of GalleryItem component are correct. But as soon as the Gallery component re renders for any reason the refs in the GalleryItem components become null values.
I have tried several things in the children components but nothing I do fixes the issue. I believe the reason is because something is happening in the code above.
I have also tried to change up the code after reading the following:
Issue storing ref elements in loop
However its not really clear to me what the person is saying to do when I look at my own implementation.
You need to move out React.createRef() from the loop (and also render) as it is creating a new ref on every render.
Depending on your code/usage, you'd need to do this in constructor and CWRP methods (basically whenever data changes).
Then creating galleryItems would be like
...
<GalleryItem ref={item.ref} />
...
I'm working on a React component library that allows for client-side data filtering by passing an array of objects and an <input/> as props to a <SearchFilter/> component. I want to return the filtered results to a separate <SearchResults/> component that can be rendered elsewhere in the tree (i.e. the results component doesn't have to be a child of the input component).
I've got the filtering figured out, but I'm not sure the best route to take in React on getting the filtered data to the <SearchResults/> component.
This is what I'd like to end up with...
<SearchFilter
data={data}
input={<input type="text" value={value} onChange={this.handleChange}/>}
/>
Then, using Render Props to return the data and map over that to return JSX, there would be the results component. Something like this...
<SearchResults
render={data => (
data.map(el => (
<div>
<span>{data.someProperty}</span>
</div>
)
)}
/>
This is what I'd like to achieve because I want to allow for rendering the <SearchFilter/> component at one place in the tree, and allow the <SearchResults/> component to be rendered elsewhere, so that there's maximum flexibility in how the tree is composed and, therefore, how the view is rendered.
I've looked into the Context API, but it seems like that would require a handful more components to be a part of my library, which further complicates what I'm trying to achieve. If that's the only way around it, then that's fine, but I wanted to ask and see if anyone can think of another solution.
Thanks!
The bigger issue is that you will need to manage a state that is shared between components on a higher level, i.e., any component that will wrap these other two components, ultimately. With plain React, this state would be managed by the parent (or ancestor) component, passing down the relevant values as props. This opposed to the, usually bad, idea to have sibling components influence each other's state, since you well get into the "who's boss here"-problem.
The thing the Context API handles is not having to pass down props for things that typically don't change (or: typically shouldn't cause renders to trigger often).
A global state store, such as Redux, can help you modelling this, but in essence it's not much more than 'a' component managing state, and other components rendering according to that state. Events within the lower components trigger changes in the data, which will cause the state to change, which will cause the props of the children to change, which then will cause re-renders.
I'd advise you to try using this simple pattern:
class Search ... {
state = {data: [], text: ""}
render() {
return (
<div>
<SearchFilter
data={this.state.data}
onSearch={() => this.fetchNewData()}
onChange={(e) => this.setState({text: e.targetElement.value})}
text={this.state.text}
/>
<SearchResults data={this.state.data} />
</div>
);
}
fetchNewData() {
fetch('/url?text=' + this.state.text)
.then((newData) => { this.setState({data: newData}); })
}
}
Something along these lines. If you have trouble modelling stuff like this, you can use Redux to force you to do it in a similar way, and avoid managing local state intermixing with global state (which is typically something that is hard to manage).
If you do this right, components that have no state (i.e., aren't responsible for managing state and thus have no event handlers) can all become pure components, i.e. stateless components, i.e. functions that return JSX based on props:
const SearchResults = ({data}) => <div>{data.map( () => <etc /> )}</div>
You could create a data store class that holds your filter, pass it in as a property to both components, and have your SearchFilter component change a value in that.
I have a react app that ties into localStorage of the browser. On the startup of the app, the localStorage is populated with all the data that is needed to run the app. This data is pulled with AJAX from XML files and constructed to form a localStorageObject that the web app can use as its "database" of information to pull content from...
At the moment, The main component's state is set to the localstorage. So essentially I have the following:
constructor(props) {
super(props);
this.state = {
courseData : JSON.parse(localStorage.getItem("storageID"));,
}
}
The state contains an object that is the entirety of the localStorage. Now I have many children components, who also have children components themselves. Some are components that just need to render once, while others are going to need to rerender with interaction from the user.
After reading, it seems there are many ways to implement a solution. I could have all the components have state, but that's not needed. I could just have the main component have state, and no other component have state. And whenever the state of the main component changes, the props will be based down and reupdated.
Is there a specific method that is best?
This method works, but.
First of all, localStorage calls should be on a componentDidMount function. Otherwise, it wouldn't work on a server-side-rendering case.
Secondly, I'd implement all the initial data fetching on a parent function and then pass down data to the root of react tree:
const localStorageData = localStorage.getItem('some_data')
ReactDom.render(
document.getElementById('my-element'),
<MyComponent
localStorageData={localStorageData}
/>
)
if have many children components it will be difficult to manage state because of deep nesting.
I would recommend using Higher Order Component for your local storage implementation And Pass it down to children. Here How I would do it:
import React from 'react';
var HigherOrderComponent = (Component) =>
class extends React.Component {
state={locStorage:{}}
componentDidMount(){
this.setState({locStorage:window.localStorage.getItem("data")})
}
render() {
return (
<Component
locStorage={this.state.locStorage}
/>
)
}
};
export default HigherOrderComponent;
import HigherOrderComponent from './HigherOrderComponent'
const ChildComponent = ({locStorage}) => {
console.log(locStorage)
return (
<div>
</div>
);
};
export default HigherOrderComponent(ChildComponent);
Total React noob here. I have two sibling Components in my React application. I want to display a Loading message in Component A when a certain method is executed in Component B
I'm familiar with passing state from a parent to child in React, but how can a sibling be notified to display it's loader?
Here's what I have so far
export default class ComponentA extends Component {
constructor(props) {
super(props);
this.state = {};
}
render(){
return(
{/* Loader */}
{ this.state.loading === true &&
<div className="loader"></div>
}
)
}
}
export default class ComponentB extends Component {
// Constructor, bindings and stuff...
getData(){
// Update Component A's "loading" state here.
// Once the data is fetched, set "loading" to false
}
render(){
return(
<div>
<button onClick="this.getData"></button>
<table>
<tbody>
{/* ... */}
</tbody>
</table>
</div>
)
}
}
Setting up both Components to inherit state from a Parent Component doesn't seem desirable because I'll have many siblings with nested Components that I'll also want to trigger this loader
Any input is appreciated!
In React, data flows from the top, down. You'd need to wrap Component A and B in a parent and keep the state in the parent as a single point of truth.
However, as you have said after a while this can become tedious when dealing with components several levels deep. You don't want to have to keep passing the state down.
I'd suggest looking into Redux (the docs are excellent) as well as the container(smart)/component(dumb) architecture.
In addition to the links above, I'd really suggest taking the time to watch this free tutorial series from Redux's creator, Dan Abramov.
Hope that helps!
First of all, you said that Component A is a child component of Component B but I don't see any relationship between the two components. But you can do one of 2 things in my opinion. One is to import Component A into Component B as a child component and pass the data to Component A as props (easy). Second way requires you to understand redux. In this case, I don't see the necessity due to the size of the app. However, basically you can have a mastermind at the top of the React component tree to pass down the state to any component. So updating the store by dispatching the new data from Component B will enable Component A to have an access to the data. Redux would be great from large applications and for data that needs to be distributed in multiple places.