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.
Related
My components are structured looks like this. Each component is it's own functional component in its own file - this is just a schematic of how they interract.
<FirstLevelComponent>
// propValue is declared on this level with useState hook.
<SecondLevelComponent someProp={propValue}>
<ChildComponent1></ChildComponent1>
<ChildComponent2 someProp={propValue}></ChildComponent2>
<ChildComponent3></ChildComponent3>
</SecondLevelComponent>
</FirstLevelComponent>
someProp is declared in state in the FirstLevelComponent and is passed along to the SecondLevelComponent and when it changes, it triggers the re-render of the entire SecondLevelComponent. But the only dependency on that prop is in one of the children. The rest of the children are unaffected.
What would be the best way to isolate that behavior and only limit scope of re-rendering to the single child that depends on that prop?
Some constraints:
This is a huge production application so something like Just add redux would not be an easy solution.
Refactoring SecondLevelComponent will be a challenge (1500 lines of code), while I am open to such opportunity`, I am looking for the way to achieve this assuming it's not a hello world project. Solutions that are easy and ideal for application in its early stages are quite a rework when we are dealing with legacy code.
and only limit scope of re-rendering to the single child that depends on that prop?
What you're looking to accomplish goes against the nature of React. If a parent component has state, and that state changes, React will react and rerender the component.
Stopping the parent component from rerendering when its state changes is an anti pattern (as opposed to simply stopping its children from rerendering with useMemo).
The way I see it, you have the following options:
Add state to the child component instead. If it's the only component reliant on this state, it should be a simple refactor.
Replace useState with useRef in the parent component. Pass this to the child for creating initial state.
Option two could lead to other implications if anything else in the app is dependant on this piece of state.
Now, if you just want to keep the extra children from rerendering, which isn't exactly what I quoted above from the question, you could just simply use useMemo (and useCallback if passing a function as a prop)..
I saw the same problem, also big application
Option 1
You can take advantage of render from React composition if you can move propValue state and ChildComponent2 component into SecondLevelComponent
Explanation: the states in SecondLevelComponent wont rerender his childs like ChildComponent1 and ChildComponent3
Option 2
You can memoize you components using React.useMemo not React.memo because you are not passing propValue in ChildComponent1 and ChildComponent3 like this:
// How to memoize
const ChildComponent1Memoized = React.useMemo(()=><ChildComponent1/>,[propValue])
// In this case ChildComponent1Memoized will not rerender again
<SecondLevelComponent someProp={propValue}>
{ChildComponent1Memoized} // <---
<ChildComponent2 someProp={propValue}></ChildComponent2>
<ChildComponent3></ChildComponent3>
</SecondLevelComponent>
Extra
if you are passing functions as props be sure you are using useCallbak in every function, because they are rebuilding in every render, that cause Memo dosent work
It seems to me that one could replace useEffect/componentDidMount with a state hook and function components. For example, if I wanted to make a fetch in useEffect or componentDidMount, I could simply create a function component that rendered the component that needed fetching, add the fetching method in the function (which will execute upon rendering) which modifies a state hook (so that once the data arrives, the page will re-render with the data). Since React has selective rendering, any other part of the function component that gets updated won't cause an unnecessary fetch.
Am I correct in saying this? Are there any other specific instances where useEffect/componentDidMount is strictly better?
Am not sure why you want to replace componentDidMount in class component or useEffect with a custom function for the use case you highlighted but those two are different in terms of behavior, componentDidMount is one functionality that useEffect provides in function component. useEffect is a combination of componentDidMount and componentWillUnmount and you can have mulitple useEffect on one function component. useEffect accept array of values that could make it run again, all you do is specify those value for that particular useCase you wanted and whenever that values changes the useEffect is called, for UI changes you attach your useState to your logic and if followed accordingly you wont get unnecessary fetch request, if you want useEffect to be called just once then attach just an empty array like this useEffect(()=>{//your fetch logic here },[])
I read the docs about useEffect and understand how it makes life more easier than life cycle methods. Yet I am wondering what would not be possible without useEffect?
E.g. instead of (all code is dummy code)
useEffect(networkRequest.then(update state));
couldn't I just use
// inside functional component
function App() {
networkRequest.then(update state)
}
What do you mean "makes life more easier than lifecycle methods"? React hooks are how you utilize component lifecycle in functional components.
Just like the render lifecycle method of class-based components is to be a pure function without side-effects, so to is the entire body of a functional component. The body of a functional component is the "render" function.
// inside functional component
function App() {
networkRequest.then(update state)
}
The above, as written, has no guard protecting the side-effect of the network request nor state update... it will simply update state and rerender, and update state and rerender, ... ad nauseam, or in other words, infinitely render loop.
React hooks are what allow you to utilize component lifecycle in functional components.
To directly answer your question though:
Yet I am wondering what would not be possible without useEffect?
It would not be possible to trigger side-effects such as any asynchronous network requests, authentication, etc... It wouldn't be possible to invoke any specific when a component mounts or rerenders. It wouldn't be possible to run any specific logic when a specific state/prop value updated.
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
I'm new in React Hooks and I'm wonder how its better to do some things. Example the state how its better to keep the state in parent and to pass to the child or to put the state in every component where I need the state? Witch is the good option?
Generally, if you use some state values in only one component, you can make it the state of that specific component, making it self-contained.
If a state is used in a component and some of its child components, it's a good idea to store it as a state in the component and pass it as props to child components.
If a state is used in multiple (relatively unrelated) components in an app, you can store it as a global state (through redux or context API) and use it in those components.