Why do we need a `props` parameter in React? - reactjs

I still don't get why we need a prop(s) in react, seriously. Why can't we just declare everything we need as an argument or parameter in the child component, then declare it, why do we have to declare it in a parent element then pass the props to the child component then catch it. I don't understand why. It seems a bit confusing, I'm yet to see the why in it

Props are useful in the case that you have a controller in the parent component and you want to pass the value of that controller to the child to make a certain action. The replacement for props would be to store everything globally in redux or mobx, but that needs much work. for example
const ParentComponent = () =>{
const [flag, setFlag] = useState(false)
return(
<div>
<button onClick={()=>setFlag(!flag)}>click me!</button>
<ChildComponent flagValue={flag}/>
</div>
)
}
as in the example for some reason the button that changes the flag is in the parent and you need to use that value in the ChildComponent. So here you benefit a lot from using props.
Also in writing a cleaner code and drier one so as not to repeat the same values in different react components

You might not be familiar with React if you ask such questions (no anger at all). It's one of the main concepts of the React library.
You can easily split a huge component into smaller pieces. But then, you need to provide the same data here and there. To prevent repeating yourself (DRY - don't repeat yourself), you can share the prop with many child components.
If you are interested in React - check the documentation.
It's one of the prettiest documentation I've ever read.

prop changes trigger UI re-render for the child component.
That's one of the props of using props.

Related

How to limit scope of re-rendering to single component in React?

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

Pass props to children directly

I want to pass my props right to my children's component.
I don't want to pass them to children and then to a decomposition component. I want to make it easier and faster.
I wondered, is it okay if I pass my props this way? Everything works as intended.
Or do I break some unknown for me rules? If I break them what can happen otherwise? If I don't break them and it's the bad approach anyway, please, explain to me why?
export function ParentComponent() {
const [myProp, setMyProp] = useState(false);
return (
<div>
<ChildrenComponent>
// Nested component gets props right here
<DecompositionComponent myProp={myProp} setMyProp={setMyProp} />
</ChildrenComponent>
</div>
);
Link to a code
P.S. I know about "render props" and useContext.
This is a perfectly valid way of sending props to components with component composition. It's also a powerful pattern to use as it can make your components more reusable, and you avoid deep prop drilling.

In React, when a parent component re-renders, isn't it true that the children with unchanged props should not need to re-render?

I think the fact is that, when a parent component re-renders in React, in general, all the children components re-render as well.
I did one experiment to confirm:
https://codesandbox.io/s/currying-pine-r16rzi
return (
<div>
<div>Time now is {timeNow.toLocaleTimeString()}</div>
<TheTimeNow /><TheTimeNow />
</div>
);
This parent component re-renders, and <TheTimeNow /> has no change in props value (it has none), but it re-renders anyway and shows the updated time.
I think it is not the same to say, that React actually change the DOM, as I think the mechanism is that React use the previous virtual DOM to compare with the new virtual DOM, and update only the minimal actual DOM node as on document.documentElement as needed.
This can be seen if you use Google Chrome and do Inspect Element on the time statement: only the time portion changes and the other English words stay the same. Compare to this where all the nodes changes if it is plain JavaScript: https://jsfiddle.net/8sj2ugae/1/ when you do Inspect Element.
However, can't we argue that, if a child is <Foo /> and since there is no props passed to it, then <Foo /> really should not have changed, and it is wasteful to call Foo()? (if Foo is a functional component, or call the render() method if it is a class component.)
Now since all children re-renders, that means all their children also get re-rendered. Repeat this rule recursively, that would mean the whole subtree gets re-rendered.
My question is: is it true that they should not need to re-render if their props didn't change, or are there other factors that make them needing a re-render really?
The answer is yes, there is no need to rerender. But in order to know this we need to compare a new props with a previous props. And this operation is not free.
Also if we do a shallow comparison we are increasing the probability of bugs. Someone might be expecting rerender after a deep props update.
Should React.memo be the deault behaviour? Will it improve the performance in most cases? We don't know. There is no evidence for that. More on this in Mark Erikson's post.
Here is a great article by Dan Abramov: Before You memo(). I consider two points regarding your question:
In the future compiler might decide when to memoize a component.
Component rendering doesn't mean that all it's children will be rerendered.
Here is an example:
const ParentComponent = ({ children }) => {
const [state, setState] = useState(0);
return <div>{children}</div>
}
If we update the state children will not be rerendered. React just uses a previous value. Here is an article by Kent C. Dobbs about this optimization technique.
One last thing. React.memo and useMemo are different. The first one is for component memoization and the second one is a hook for expensive calculations. There are also shouldComponentUpdate for class components and PureComponent which compare not only props but also a state.
Hopefully the answer and links will shed some light on this topic.

Data flow in React app w/ functional components & hooks

I'm trying to wrap my head around the data flow in a React app w/ functional components & hooks.
I'm wondering:
When a data change (state change) causes a cascade of code to execute... what code (say, in each component, does and does not run... apparently there is selectivity such is "don't put that variable in the deps array if you don't want that code to run")?
How is the "family" part of the family tree determined during such a data-cascade? Does data pass to siblings? Does it only go to a child (or a parent if a function was passed down for updating the parent)?
To clarify what I have in mind, I have ended each file name with a labeling convention like so: I claim that (and request corrections!) 1 is the parent of 2; 2 is the parent of 3a (I think... can a custom hook be a "child"?), 3b, and 3c; and 3c is the parent of 4c.
Clearly parent/child data flow is a natural part of React. What about sibling to sibling? Is that where problems happen? Certainly "passing data" within a given file can be dangerous (vis-à-vis having control over if and when rendering of a piece of data happens) and apparently the solution is to "lift" the data up the tree. But even still... there is no sense in lifting data up a level (or more) if it isn't clear how it trickles back down... and what problems we should be looking our for.
index1.tsx
...
<App/>
...
App2.tsx
...
const App = () => {
...
const {varFromCustomHook} = useAppLogic(varToCustomHook);
...
<FooComponent varToFoo={varToFoo} functToFoo={functToFoo}/>;
<BarComponent/>;
...
};
...
useAppLogic3a.tsx
...
interface Props {
varToCustomHook;
};
const useAppLogic (props: Props) {
...
return {varFromCustomHook};
};
FooComponent3b.tsx
...
interface Props {
varToFoo;
functToFoo;
}
const FooComponent = (props: Props) => {
...
funcToFoo(importantData);
...
<div>{varToFoo}</div>;
...
};
BarComponent3c.tsx
...
const BarComponent = () => {
...
<FoobarComponent/>;
...
};
FoobarComponent4c.tsx
...
const FoobarComponent = () => {
...
};
A react component is a react component, whether it is a class-based component or a functional component is an implementation detail. Data flows down the react tree, parent to child, in the form of props. This is a universal truth in React.
When a data change (state change) causes a cascade of code to
execute... what code (say, in each component, does and does not run...
apparently there is selectivity such is "don't put that variable in
the deps array if you don't want that code to run")?
When state and/or props update, the functional component is rerendered. The entire function body of a functional component is technically the "render" function, so all of it is run when the component renders.
You ask specifically about hooks. Hooks are also executed each render cycle, in the order they are declared, and if there exists a dependency array, it is evaluated and if any dependency fails shallow reference equality check then the hook's callback is triggered.
How is the "family" part of the family tree determined during such a
data-cascade? Does data pass to siblings? Does it only go to a child
(or a parent if a function was passed down for updating the parent)?
The React tree is determined the same way it has almost always been determined, a root node, and children, where each child component can have further children. Data is still passed only from Parent to Child. Callbacks are still passed as props (generally) for a child component to invoke.
Comment Questions
Is useAppLogic considered a child [of App in this case], or can custom
hooks not be considered children (for whatever reason)? Assuming the
answer is yes, then couldn't useAppLogic return a value that gets
passed to its sibling, FooComponent? If yes, wouldn't this be data
flowing "horizontally" and not down? I don't know the answer... but it
seems like this kind of data-pass is possible (maybe it is an
anti-pattern, I don't know).
No, useAppLogic is a react hook and can't be a child of anything, it's a function. Only react components, HTML elements, and primitives (string, number, etc.) can be a child, rendered as JSX. Data flows only down. If data needs to be passed to siblings it needs to be lifted to at least the nearest common ancestor. If useAppLogic is in App, and FooComponent is a child of App, then any value returned by the hook can be passed as a prop to FooComponent.
What if (in the above case we have been discussing in these comments)
useAppLogic was use by both App and App's child, FooComponent? Would
this be an anti-pattern? This would apparently allow a parent and a
child to have a piece of data that was not "passed down". (To go out
on a limb... is this a window into a conversation on global
data/useReducer?). Maybe these points here in the comments would help
some people if they were in the answer.
React hooks are each their own instance. They don't share any state, or anything else for that matter. There isn't enough context to say whether or not both parent and child component using the same react hook is an anti-pattern, but I'm inclined to say no, it isn't, since any functional component can use any react hook for just about any reason. Not a window into any global data (useContext hook would be about as close as you could get to some "global" data).

React props vs children. What to use when?

What is the difference between the two approaches ?
Passing text for a button as props
<TextComponent title="Save"/>
function TextComponent(props){
return <button>{props.title}<button/>
}
vs
Passing text as a child
<TextComponent>Save<TextComponent />
function TextComponent(props){
return <button>{props.children}<button/>
}
children prop is something that you use when the structure of what needs to be rendered within the child component is not fixed and is controlled by the component which renders it.
However if behaviour of the component is consistent across all its renders it can define the specific props that it needs and the parent can pass them to it.
A very simple example could be a Navbar which can use children. For a Navbar the items that it needs to render as well as the order or alignment or items depends on how it needs to be used at different instances or across different pages. For instance Navbar somewhere can have Search component at one place and at some other place not have it. Also the menus may sometimes be needed to the left followed by Login menu item to the right and a searchbar between them and sometimes they may all be present to the right without the searchbar. In such cases the parent component can control how the internal structure would be
You should use children when you don't know them ahead of time, see: https://reactjs.org/docs/composition-vs-inheritance.html
Here, if you KNOW that you'll use a title inside your child component, just use a named prop.
I'd say that if you ask yourself the question: "Ok, but what will that generic component render?" is when you should use children
You use props.children on a component which acts as a container and does not know about their children ahead of time.
Basically props.children it is used to display whatever you include between the opening and closing tags of the "containing" component when invoking it.
As mentioned in the React official docs:
Some components don’t know their children ahead of time. This is especially common for components like Sidebar or Dialog that represent generic “boxes”.
We recommend that such components use the special children prop to pass children elements directly into their output:
Simply put, it props.children just displays whatever is put between the opening and closing tags.
As asked in your question, there is not much difference in the use case specified by you.
But, say you had a small left icon the component then passing 'title' as a separate prop would make more sense Eg.
<TextComponent title="Save" src="https://..." />
function TextComponent(props) {
return (
<div>
<img src={props.src}/>
<button>{props.title}<button/>
</div>
);
}
When you do know what your props are, use props. Otherwise, use children (aka containment).
Other than that, using props/children in your case depends on what you want to pass:
If its a single props (like item), than it doesn't matter which method you'll choose.
Else, you should check what you are passing inside children as you might pass other values which you don't want to render.
I would suggest using the selective approach (e.g props.title), since you are always aware of whats going inside your components.

Resources