How to prevent unnecessary render when fetching static content? - reactjs

When I use react hooks I declare my state to be like this:
const [entities,setEntities] = useState([])
Then I make an api call to the server that return static content that never changes.
I setEntities(fetchedData) and what is actually happening is that I render the component twice - Once when the array is empty and the second time is when the data arrives. The data is static and it never changes. Was wondering if there is a certain way to prevent this unnecessary render? I thought the solution will be to make the api call on componentWillMount but there isn't any parallel solution with hooks to this, as this method is not used anymore.

If you really want to render that component only once, you could move the fetching logic to it's parent.
In parent:
fetchData();
entities; // where the data from request is stored
Then use a basic render condition:
{entities && <Child entities={entities} />}
Then, wrap the Child component with React.memo to avoid re-renders if parent re-rendered.
export const Child = React.memo(() => {
...
});
Finally, what is most important - operate over props, do not save it inside state. So if you want to do something with the entities, use it as props.
{props.entities.map(...)}
The Child will render only once, when entities data is received from API. If only you won't call API anymore, it will stay at it is.

componentWillMount are considered legacy and you should avoid them in new code. https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html
And you cannot render data once.
UPDATE:
In future Suspense should help. https://reactjs.org/docs/concurrent-mode-suspense.html

Whenever you make a call to the client from a react component the double rendering will happen. For that particular case, I recommend you to use ReactDOMServer
The ReactDOMServer object enables you to render components to static
markup. Typically, it’s used on a Node server:
Or if you did'nt start your project yet you could try using a server-side render framework like nextjs

Related

React useEffectin App.js before children component renders

In my React App.js component I execute the following code:
function App() {
const dispatch = useDispatch();
useEffect(() => {
dispatch(getAuthenticatedUser());
}, []);
This code fetches the current authenticated user by session from an API and will fill the redux store. However this code seems to run after the children of App are rendered. The children components use state variables, because this function is executed after my child components are rendered it won't work. I need this function to be called once before I render my child components within App.js, how can I achieve this?
You can't ask React to delay rendering, that's just not how React is supposed to work (unless you're using experimental features like Suspense, but you should probably learn idiomatic React first).
You normally simply tell React what to display depending on the current state/props, and React will automatically rerender as soon as something changed.
So if you have no state variable saying that the app is in a loading state, you should make one. After all, whether it is currently loading or not is intuitively part of the current "state" of the app, especially if you are on a slow connection for instance.
You could just do something like a ternary that only renders those children when these variables are available, something like:
variables ? <Children/> : <Loading/>
Suspense is a great experimental feature that could help you handle this if you're willing to be an early adopter!

How to initialise state stored in separate components from a single async request?

What I would like to do:
I have various self-contained components, that manage their own state within themselves. The state of each component should definitely be handled within each component.
Their initial state comes from the back-end. After this they maintain their own state.
I don't want to make lots of separate requests for each component, so I make one request to fetch the data for all of the components, and pass this down which provides initial data for each component.
My current Solution:
const MyApp = () => {
const [initialState, setInitialState] = useState();
useEffect(()=>{getInitialState().then((data)=>{
setInitialState(data);
})},[])
if (!initialState) {
return <div>Loading...</div>
}
return (
<>
<ComponentA initialData={initialState.A} />
<ComponentB initialData={initialState.B} />
<ComponentC initialData={initialState.C} />
</>
)
}
Problems with my current solution:
The above works, but it doesn't feel right. I've called the above initialState but it shouldn't be state. It's much more like a prop, and it's confusing to store the initial data for the entire life-time of the app. Admittedly, it's not doing anything, and doesn't cause any harm, but if it's not being used by anything, why keep it there?
I considered fetching the data before I even rendered the app, and then passing the data in as a prop, but then I would have nothing displayed rather than a loading screen, so that didn't seem like a good approach either.
My Question:
Is there a better (and/or standard) approaching for achieving the above? (I'd like to use hooks rather than classes). Perhaps the above isn't such a bad idea, but it feels like there must be probably a better way of doing it without resorting to 'global' app state. I would like to keep my state close to the components where the relevant parts of it are used.
There is nothing wrong with using state here. However, assuming that getInitialState is only supposed to be called once, I would wrap it in the useEffect hook, such that the data is only fetched once when MyApp is mounted. This will prevent getInitialState from being called repeatedly when the component re-renders.
useEffect(() => {
getInitialState().then((data)=>{
setInitialState(data);
});
}, []);
If you do not wish to use state to maintain the data, you will have to rely on the Context API, or use some kinda state management library such as Redux.

Using useEffect fetch data several times

I'm just new to React Hooks, and playaround with it.
Just wondering if there any solutions that I could use useEffect to fetch data several times after componentDidMount.
Normally we use useEffect to fetch data based on some props change by passing them.
useEffect(()=> {
fetchApisomefunction()=>{}
},
[]); // normally do this for componentDidMount
How can I fetch data again after that?
UPDATE
callback function could solve this.
Assuming that you are not using Redux or Context API,
so component A and B are not communicating to each other directly.
On the other hand, there will be a parent component which joins those two components.
As you've said, component B will post the data, and that should change parent's state.
Since react child component is being re-rendered whenever its parent component's state or props change, component A will also be re-rendered.
So all you have to do is to use useEffect without second parameter [].
Actually it is not the question of using Hooks, but the question of react component structure.
Keep in mind that the two child components should not directly communicate to each other.

It's a good pattern to put function in a ReactJS state?

I don't feel right to store a function in a reactjs state, but not sure any disadvantage? Could anyone help analyze it?
view1: function() {
return <div>view1</view>
}
view2: fucntion() {
return <div>view2</view>
}
goView1: function() {
this.setState({contentView: view1})
}
goView2: function() {
this.setState({contentView: view2})
}
render: function () {
return(
{this.state.contentView()}
)
}
There're a few common gotchas about state in react:
Don't mutate state directly, use setState instead
Don't use state when not referenced in render, use instance variable instead.
Well, it seems fine to use state as function, since it's used in your render function to return what to render? Alright, it might not be an anti-pattern, but a better place to put those functions might be in your props, aka render prop, a few reasons:
Think state as your component's data model.
Data are not stale, it changes over time, it could be results from async operations, ui states after user interactions, controlled forms values etc.
Just like redux stores your app's global state, react state should store your component's local state that changes over time, while functions most of time, does nothing more than deferring execution.
Render props is different, it offers IoC (Inversion of Control) for free.
Props most of time similar to local state, should be concerned with UI rendering. However, unlike state owned/managed by component itself, props are passed from parents/clients of the component.
Event handlers for example, event target (usually DOM elements like button, input etc) doesn't need to know how to handle events when creating the component, instead it yields control back to component client/consumer who might need to use setState in its handleEventName handler to update certain container's state shared across children.
Some library (e.g., react router4) also shifted from HOC to render props (e.g., react 16.3 new context API - provider/consumer pair) in favor of its flexibility and explicitness. Instead of composing HOCs before runtime for static version of final enhanced component, you can declare what to render using render props and composing them at runtime in render functions. Thus, you get a clear separation between data (state/props) provider and consumer (where render props are passed from).
Regarding any performance (re-render) concerns, i think it's totally fine to use state as function, since most performance tricks are done by using shouldComponentUpdate hook with shallow compare state/props references (e.g. React.PureComponent, Redux Connect etc), so it's where immutability and memoization comes into play.

Set state after component did mount?

A story:
I have a server rendering but some part of my app cannot be done there, since they use document(react-art library for drawing on a canvas).
I cannot render everything in the same from, because react will say that the code received from a server and and client one are not the same.
So my solution is to render some part of my app on the server, then render this part on a client and, in the next frame, render everything that is impossible to render on a client.
So I was thinking about using setState in componentDidMount and trigger DOM update, so it can contain rendered client part which cannot be rendered on a server, but eslint says it is not good to set state in componentDidMount. Logically I cannot say why it is bad in this case. Generally it is not good because it triggers DOM update, but in my case, this is what I actually need.
What would you suggested in this case?
Edit 1:
Fixed typo, I mean componentDidMount not componentDidUpdate.
Edit 2:
Here is the same issue, but they use changing state in componentDidMount as a workaround.
I've just coded a similar scenario and happily used componentDidMount disabling ESLint's warning. IMHO it is perfectly valid ONLY in universal rendering scenarios.
Why: Using setState in discouraged in componentDidMount because you'll trigger an additional, unnecessary render.
However in a universal scenario where you want to differ server and client behaviour, you'll want that additional render and in order to prevent 'could not reuse markup' errors, you'll want it just after react reconciles with the server rendered DOM. In brief: You'll render twice in any case.
I don't however recommend coding this behaviour in a leaf / dumb component because doing so would require the supposedly dumb component to have some knowledge of it's environment (client / server) and present a design problem. Creating a component that would set the props of the dumb component would be the obvious solution.
Try setting state in componentWillMount or componentWillUpdate.
Be careful with componentWillMount, it can also be called server side.
What i understand from your question is that after your component is mounted, data on server and client changes and you want to keep component in sync with changing data.
I recommend you have a look at the flux or redux architectures of react. For example flux is implemented in a way that when anything in component changes it triggers action and listens to the store. And when anything in store is changed then component will re render itself.
Please see this link About ReactJS - Component Life Cycle.
you should use from componentWillMount cycle. componentWillMount is executed before rendering, on both server and client side.
I want to know how to trigger components update after my app is mounted.
In React, the conventional way to "push" state onto a component is using props, not state. If your application needs to acquire information client-side and adjust component state accordingly, you should implement componentWillReceiveProps.
If you feel that the state rendered on the server and in-browser are of the same kind, and don't want the hassle of tracking which properties belong this.state v. this.props, I suggest something like the following:
componentWillReceiveProps(nextProps) {
this.setState( Object.assign({}, this.state, nextProps) );
}
This will merge the passed properties into the component state, so that they can be accessed using this.state.
Prevent usage of setState in componentDidMount.
Updating the state after a component mount will trigger a second render() call and can lead to property/layout thrashing.
The following patterns are considered warnings:
class MyComponent extends React.Component {
componentDidMount(){
this.setState({
data: data
});
}
}
The following patterns are not considered warnings:
class MyComponent extends React.Component {
constructor(){
this.setState({
data: data
});
}
componentDidMount(){
...
}
}

Resources