React useEffectin App.js before children component renders - reactjs

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!

Related

React hooks queries

I have the following queries -
What's the difference between useEffect, useMemo and useCallback hooks ? I have gone through many examples and explanations but still am not clear on their difference. All I know is that each executes only when at least one of their dependencies change.
If useRef hook allows us to persist with values between re-renders, why not use a simple variable (not a state) for the same ? I read somewhere that if not changed manually, useRef will have the same value all the time. Can't we achieve this with a simple variable ?
tl;dr
useMemo fired immediately, useCallback not.
local variables a not persisted between renders
Explained
useMemo and useCallback area really very same. The difference between them are mentioned in the hooks names.
useMemo is created for calculating some heavy things (like taking some very long list and mapping it in another) and storing it for some time – as documentation says React can drop useMemo result and make hook to run again. When component is rendering first time, all useMemos continuously runs calculations and their results may be used during the render. When rendering next times (if no hook dependencies changed) React do not call passed function but just using memorized result.
useCallback is created just for preserving variable references to functions that is passed as first argument. It is very helpful when callback, created with that hook is passed to some children components cause persistent variable reference do not invalidates memorized components.
Small example:
const app = () => {
console.log('app render starts')
const title = React.useMemo(() => {
console.log('running calcualtion!')
return 'Hello world'
}, [])
console.log('app render continues')
const handleClick = React.useCallback(() => {
console.log('handling click')
}, [])
console.log('app render continues again')
return <div onClick={handleClick}>{title}</div>
}
/*
Output after mounting app:
- app render starts
- running calcualtion!
- app render continues
- app render continues again
And after clicking div:
- handling click
*/
About useRef
React functional components are functions that runs again on every component render. Without hooks that functions are totally pure and unable to contain any state or preserve variables value – all function-scoped variables are created on every render again.
Hooks know which component are currently being rendered, so hooks able to store some data about component and get it back when component re-rendered.
In lot of cases useRef really are just a way to persist value between renders. As described above, you can't achieve that with simple variables inside of component's function. It could be achieved with some global variable declared outside of component. It even may be better choice if variable value do not depends one component mount/unmount which are handled by useRef.

how to stop react-piano-roll component from duplicating itself on state update

i have a react component in which im using react-piano-roll component, the problem is when i update my component's state, react-piano-roll component replicates itself,
here is link code https://codesandbox.io/s/prod-water-q3eg4p?file=/src/App.js
thank you for your time and suggestions
I have been struggling with this same issue and I had a look into the PianoRoll react component itself. The culprit section seems to be:
useEffect(function () {
container.current.appendChild(pianoRoll.view);
});
After changing the section to read:
useEffect(function () {
container.current.replaceChildren(pianoRoll.view);
});
the component seems to function as intended. From my understanding, useEffect runs on every render which is triggered by setState. As the append code is running each time useEffect is being triggered, the element is being duplicated each time.
My only fix I can see at the moment, unless the base react component is updated, is to make a copy of the component manually and call that instead.
https://codesandbox.io/s/boring-mopsa-cppq2v?file=/src/App.js

How to dispatch slice reducer from a library not a React component

I'm currently building a React application based on https://github.com/react-boilerplate/react-boilerplate-cra-template.
This boilerplate, uses Redux with slices. Which works fine, as long as I want to update the state from within a React component. However, I am struggling with updating my application state from somewhere else. In my particular case I want to dispatch a logout event as soon as I get a response that I am unauthorized, basically resetting the application state.
Now this obviously can happen in any API request and therefor I don't want this to handle within the React component and rather handle it in my API library that handles API requests.
From what I've read so far, I should be able to dispatch an event by simply accessing the store. In this boilerplate the store is defined in the src/index.tsx file. So after adding the export keyword to it I thought I would be able to do this:
import { store } from 'index';
import { appActions } from 'app/slice';
console.log(store.getState());
store.dispatch(appAction.logout());
Somehow the state here is always undefined, even tho there is a state when I access it via a React component. Also the reducer called above never picks up the dispatched event. I also tried to encapsulate it with a timeount, in case this is just because the store isn't initialized yet, but that's not the case.
I'd appreciate your help :)
Please try to check the path is correct to get to the store.
After that please try again. I think your method is right.
If it is not working, please try to use the require method
require('index');
require('app/slice');
​
console.log(store.getState());
store.dispatch(appAction.logout());
​
Ok, here is how I finally made it work:
I imported the React hook of my slice into the src/app/index.tsx file
import { useAppSlice } from 'app/slice';
export function App() {
// use the React hook
useAppSlice();
return (
<BrowserRouter>
...
</BrowserRouter>
);
}
Even tho I'm not using the slice in this particular controller, it somehow "connects" with the store, so that I can use the slice from within any sub-controller or any library.

How to prevent unnecessary render when fetching static content?

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

react native re-rendered components multiple times

In react native, I use some component like audio player, header etc. Also, I use console.log() for debugging for component I put log in start of components :
const MiniPlayer = (props) => {
console.log('Begain Mini Player ....');
return()
}
I got multiple logs, it's re-rendering is happening multiple time without any special event or state change.
app hasn't any issue and not working slow.
Should I control this re-rendering or is it common in react ?
As per your given snippet, MiniPlayer will re-render whenever its parent component re-renders. It's how react works. If a component updates, its entire subtree re-renders regardless whether the children components need it or not. To control it, you can use shouldComponentUpdate in a class component or extend the class with PureComponent, or wrap your component with React.Memo if it's a functional component. Since yours is a functional component, we can make changes to your component so that it re-renders only when its props change as follows.
const MiniPlayer = React.Memo((props) => {
console.log('Begain Mini Player ....');
return()
})
More resources here - shouldComponentUpdate, PureComponent and React.Memo
Also remember that using React.Memo is just going to perform a shallow comparison of props. So even if the values of props are equal but if the reference changes, it would still cause a re-render.
Should you control this re-rendering? Well that depends. If your component is a costly one which performs heavy computations whenever it updates, then you should control this, else it is not going to affect much, as the DOM anyways is going to perform a diff check to determine what is supposed to be updated.

Resources