Changing the state of a React Component - reactjs

Maybe it's the way I am wording things, but I am not getting the answer I want on the following topic. So currently, my code looks like this (minus all the details):
<ClickAwayListener onClickAway={handleClickAway}>
<Autocomplete options={someList} />
</ClickAwayListener>
So I have two questions.
Is Autocomplete component here considered to be an extension of ClickAwayListener? Is ClickAwayListener considered a parent component?
I want the handleClickAway function to change the options state within Autocomplete. How would I go about doing this?
I am pretty new to React, so I would appreciate any and all help. Thank you in advance.

It looks like most likely you are using your click away component not in a way it was intended to be used. It looks like it should be used with this technique.
<ClickAwayListener onClickAway={handleClickAway}>
{(isClickedAway) => (
{/*or whatever api your Autocomplete has*/}
<Autocomplete options={someList} isOpen={!isClickedAway} />
)}
</ClickAwayListener>
As to your questions:
ClickAwayListener is a parent of Autocomplete. There's no such thing as extension in react tree.
in your handleClickAway you have to change someList. If it comes through the state, then with setState, if it comes from props - with a corresponding callback.

Related

MUI Autocomplete, renderInput prop: What is (are) params?

I'm learning how to use MUI's Autocomplete component, and I'm struggling to understand the renderInput prop. I get that it exists to specify how you're going to display the component, but I don't understand how it works. In particular, what is the params object that is passed into the function? What does it contain? How am I supposed to use it?
I've been doing a lot of web searches and have failed to find a good resource to explain this. The documentation's description of the prop is "Render the input", which drives me a little crazy.
Any help elucidating would be very much appreciated. Thank you!
The params contain the props needed for the input element and the container around the input. It allows you to make your own custom input using the functionality provided by MUI.
This is from the MUI docs Autocomplete custom input section.
renderInput={(params) => (
<div ref={params.InputProps.ref}>
<input type="text" {...params.inputProps} />
</div>
)}
You can always check for the params by a simple console.log

Arrow function vs Component React

I recently made a pull request at my company and got feedback on some code that I had written and I wanted some other opinions on this.
We have an component called Icon that can take another component as a prop like so:
<Icon component={ArrowDown}/>
this simply renders the following:
<IconContainer>
<ArrowDown/>
</IconContainer>
Now you can also do the follow if you need to create a custom icon:
<Icon component={()=><div>custom Icon</div>}/>
The reviewer commented that the function ()=><div>custom Icon</div> should be removed outside the scope for performance reasons to prevent re-rendering:
const CustomIcon = ()=><div>custom Icon</div>
const someComponent = ()=><Icon component={customIcon}/>
I'm not convinced that this will improve performance (code-readability sure) but wanted to get some other opinions on it.
Thanks!
Arrow functions are anonymous and will be re-instantiated on every render.
If you create a named component, it will have a reference and will not be re-rendered by React unless and until required (through state update).
And also, as you mentioned, it provides better readability and an option for code splitting.

React.forwardRef is already possible without it, so what's the use of it?

I'm confused on the point of React.forwardRef. As explained in its documentation, I understand that its main use is for a Parent Component to gain access to DOM elements of the Child Component. But I can already do that without even having to use it.
Here is a code example that you can plug into CodeSandbox and see that it works:
import React, {useRef, useEffect} from "react";
import "./styles.css";
const ChildComponent = (props) => {
useEffect( ()=> {
props.callbackFunction()
})
return(
<div ref={props.fRef}>
{"hello"}
</div>
)
}
export default function App() {
const callbackFunction = () => {
console.log("The parent is now holding the forwarded ref to the child div: ")
console.log(forwardedRef)
}
const forwardedRef = useRef(null)
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<ChildComponent name="gravy" callbackFunction={callbackFunction} fRef={forwardedRef}/>
</div>
);
}
Or here's the embed of this example. Honestly, I'm kind of new to this and I don't know exactly how embeds work and whether someone fiddling with the embed changes my original Sandbox or not, so I was hesitant to put it. But here it is.
Example Forwarding Ref
In the example, the parent App() component successfully passes a ref to the child which the child attaches to its rendered div. After it renders, it calls a callback function to the parent. The parent then does a console log where it proves that its forwarded ref now has a hold of the child's div. And this is all done without React.forwardRef.
So what then is the use for React.forwardRef?
You're absolutely right that you can do what you've described. The downside is that you're forced to expose an API (ie: the fRef prop) for it to work. Not a huge deal if you're a solo developer building an app, but it can be more problematic eg. if you're maintaining an open-source library with a public API.
In that case, consumers of the library won't have access to the internals of a component, meaning you'd have to expose it for them somehow. You could simply do what you're suggesting in your example and add a named prop. In fact, that's what libraries did before React 16.3. Not a huge deal, but you'd have to document it so people know how to use it. Ideally, you'd also want some kind of standard that everyone used so it wasn't confusing (many libraries used the innerRef naming convention), but there'd have to be some consensus around that. So all doable, but perhaps not the ideal solution.
Using forwardRef, passing a ref to a component just works as expected. The ref prop is already standardized in React, so you don't need to go look at docs to figure out how to pass the ref down or how it works. However, the approach you describe is totally fine and if it meets your needs, by all means go with that.
As mentioned in the docs , it's useful for highly reusable components, meaning components that tend to be used like regular HTML DOM elements.
This is useful for component libraries where you have lots of "leaf" components. You've probably used one like Material UI.
Example:
Let's say you're maintaining a component library.
You create a <Button/> and <Input/> component that maybe just adds some default styling.
Notice how these components literally are just like regular HTML DOM elements with extra steps.
If these components were made to be used like regular HTML DOM elements, then I expect all the props to be the same, including ref, no?
Wouldn't it be tedious if to get the button ref from your <Button/> component I'd have to get it through something like fRef or buttonRef ?
Same with your <Input/>, do I have to go to the documentation just to find out what ref to use and it's something like inputRef ? Now I have to memorize?
Getting the ref should be as simple as <Button ref={}/>
Problem
As you might know, ref will not get passed through props because, like key, it is handled differently by React.
Solution
React.forwardRef() solves this so I can use <Button ref={}/> or <Input ref={}/>.

Real-Time use case of this.props.children

I have read many articles to find out the real time use case of this.props.children but i didn't find the answer that i am looking for.I know that this.props.children is used to access the data b/w the opening and closing tag of a component. But my question is why can't we add a prop to the component instead of writing data b/w opening and closing tag.
for Ex:
<Example>This is data<Example> //can be accessed as this.props.children
can be written as
<Example data="This is data"/> //can be accessed as this.props.data
Can somebody please explain me with a real-time example of where we can achieve a certain task by using only this.props.children?
For example if you have complicated children of a component:
<Card>
<div class='title'>Title</div>
<div class='content'>Content</div>
</Card>
It would be easier than if you write like:
<Card content={[<div class='title'>Title</div>, <....>]} />
Samething you can find here, for example in Drawer component of Material-UI here. Drawer is a component that slides from the left, it can contain anything, so using props.childrens.
While making an app, you want a parent component which will render anything in your component. The use cases which I can think of are:
When you want to open a different component depending upon the route change.
const App = ({ children }) => (
<div className="full-height">
{children}
</div>
);
When you want to have same styles throughout your app for generic elements such as body, head etc. You'll just have to apply on this component, e.g., in above example, the full-height will get applied everywhere in the app on top component. (Obviously there are other work arounds but this is always more clear)
For use cases where you want to expose your component (when component doesn't know children ahead of time) as libraries and props can vary a lot and complicates the rendering. Read this
Obviously you don't have to use it but it makes code more elegant and understandable.

react willReceiveProps workaround for external library

I'm using a react datepicker component that can be found here. The component is pretty great except for what appears to be an oversight: it does not implement willReceiveProps.
To expound, I create the datpicker as below:
<DateField
dateFormat= { dateFormat}
forceValidDate={true}
defaultValue={startDate || ''}
onChange={this.handleChange.bind(null, 'start_date')}
id="start"
>
<DatePicker
navigation={true}
locale="en"
forceValidDate={true}
highlightWeekends={true}
highlightToday={true}
weekNumbers={true}
weekStartDay={0}
/>
</DateField>
Note above that there is a prop defaultValue which I pass startDate. Now, startDate can and does change for reasons that are sometimes external to the component. That value is passed during a new render() action as per usual. According to react philosophy this shouldn't be a problem.
However, it appears to me as if the value from defaultValue is only ever read once inside DateField. It is read as this.props.defaultValue. Anyone who has ever built a component relying on props should quickly recognize this is a problem. It means that when the prop is changed the new value will not be used.
Because this is a library, I cannot simply implement willReceiveProps. Does anyone know of a good workaround to get this component to either completely reset on a render or some other strategy to deal with what seems to be a big design problem?
They follow the same standards as the <input> component. defaultValue is read only once but there is also value that can be set externally. There is no need for them to use willReceiveProps.
In short, use value instead of defaultValue.
See Uncontrolled Components in React
PS: I am looking a bit into the code and it seems there are also properties text and date apart from value. Since the code (and documentation) has been removed from github, I won't inspect what is the difference between those props.

Resources