Arguments instead of Props in React Functional Component - reactjs

Is this function correct React Functional Component? Or why should I use props object?
function StyledLabel(value, cssClass){
return <span className={cssClass}>{value}</span>
}
Only difference I see is in calling this function:
<App>
{StyledLabel(value, cssClass)}
</App>

function StyledLabel(value, cssClass){
return <span className={cssClass}>{value}</span>
}
being used like
{StyledLabel(value, cssClass)}
isn't a traditional functional component but a function that returns JSX.
If you follow such a syntax, you won't be able to leverage some functionalities of a functional component such as using React.memo.
Although you can still use hooks within the functional component.
The other drawback of using such a syntax is that you cannot easily add children components to StyledLabel like you do with the following syntax
<StyledLabel>
<SomeChild/>
</StyledLabel>
Although internally React too invokes the function by calling it and JSX render is a just a Syntactic Sugar that uses React.createElement to transpile it but it provides you with a way to make the component a part of the Virtual DOM instead of its return value being part of virtual dom

Function Component is a function which returns JSX element.
That's a Function Component which invoked as a normal function.
But in this case is hasn't invoked with React.createElement.
Because JSX is syntactic sugar for React.createElement, you need to invoke the function with JSX syntax like so:
function StyledLabel({ value, cssClass }) {
return <span className={cssClass}>{value}</span>;
}
<App>
<StyledLabel value={value} cssClass={cssClass} />
</App>
Without invoking React.createElement, React won't be aware of the component (for state updates, diffing algorithm etc.), as it will be just a normal function call.
Yet another major problem is the function arguments:
// Not function StyledLabel(value, cssClass)
function StyledLabel(props)
React.createElement accepts a single argument which is the component's props.
React.createElement API
React.createElement(
type,
[props],
[...children]
)

Related

Why can't a Higher Order Component (HOC) directly return it's component argument?

I'm learning about Higher Order Components in React and I encountered some code that is very confusing to me.
function HOCFunction(Component){
function handleComponent(){
return (<Component/>);
}
return handleComponent;
}
^^^ This code will work and run normally. The HOC function takes a Component as a parameter, creates a functional component, and then returns it.
So here is my question...
function HOCFunction(Component){
return (<Component/>)
}
^^^ This code throws an error "Warning: React.jsx: type is invalid..." I would expect this code to work as well. Why can't I directly return the component passed in as it's argument?
Is there something about JSX that I don't understand?
Edit - Here's how I'm using the HOC.. I'm using react native btw
const TextComponent = HOCFunction(() => {
return <Text>this is text from a hoc</Text>
}
And then 'TextComponent' could be rendered like so..
function ParentComponent(){
return( <TextComponent/> )
}
I would have expected to be able to return the component parameter directly, but in order for the code to run, it seems like I have to create a separate component inside the HOC function. Why is that?

"Introduce Prop" refactoring in WebStorm for React for functional components

In WebStorm and JetBrains IDEs there's a very handy refactoring tool named "Introduce Parameter" which takes the selected text and converts it to a parameter and replaces any calls to the function with the original selection as a parameter. It is available by selecting an expression inside a function, right clicking, Refactor > Introduce Parameter or through shortcut Ctrl Alt P.
For React functional components, parameters are passed as props which is a JavaScript object that contains all attributes passed to the JSX tag.
Is there a similar refactoring action available to introducing a prop to a functional component?
Example:
Before:
function ChildComponent() {
return <div>Hello World</div>
}
function ParentComponent() {
return <div>
<ChildComponent/>
</div>
}
User selects Hello World in editor and uses shortcut for hypothetical Introduce Prop action
After:
function ChildComponent(props: { helloWorld: string }) {
return <div>{props.helloWorld}</div>
}
function ParentComponent() {
return <div>
<ChildComponent helloWorld={"Hello World"}/>
</div>
}
If a whole tag block is selected instead of a string the type of introduced prop would be JSX.Element.
If this functionality is not available natively through WebStorm, is there functionality to add the refactoring customly or perhaps is there a plugin for it?

Have a method call another method within a function component

I am using a component called DocumentPicker from the Fluent UI library.
This components has several methods:
<DocumentPicker
removeButtonAriaLabel="Remove"
onRenderSuggestionsItem={SuggestedBigItem as any}
onResolveSuggestions={ /* do some stuff here */ }
onRenderItem={SelectedDocumentItem}
getTextFromItem={getTextFromItem}
pickerSuggestionsProps={pickerSuggestionsProps}
disabled={isPickerDisabled}
inputProps={inputProps}
/>
For my specific scenario, I'd like to have a method of this component call another method. For example, have onEmptyInputFocus trigger onResolveSuggestions. How can I accomplish this?
[edit] Basically I am trying to accomplish with a function component what I would be able to do using "this" on a class component. In my class component I could write something like:
public onEmptyInputFocus () {this.onResolveSuggestions();}
Since you specify these methods, it's pretty easy:
const _onEmptyInputFocus = () => {
onResolveSuggestions()
}
<DocumentPicker
removeButtonAriaLabel="Remove"
onEmptyInputFocus={_onEmptyInputFocus}
onRenderSuggestionsItem={SuggestedBigItem as any}
onResolveSuggestions={onFilterChanged}
onRenderItem={SelectedDocumentItem}
getTextFromItem={getTextFromItem}
pickerSuggestionsProps={pickerSuggestionsProps}
disabled={isPickerDisabled}
inputProps={inputProps}
/>
I think I am pretty clear now that it cannot be accomplished with function components. You would have to know the internals of the component and tweak it.
A workaround is to use a ref and work with the underlying HTML element. In Fluent UI the prop is actually called componentRef, not just ref.

Component has props as function the containsMatchingElement returns false

When a component has props as function the containsMatchingElement returns false. When I used debug, I could see the component. So, for testing purpose I removed the function props from the actual code and the test passes. Does anyone know how to make the test pass with the props as function in a component?
expect(parent.containsMatchingElement(
<Child test="foo"setSeverityLevel={jest.fn()}/>
)).toBe(true);
Can you try it like this?
expect(parent.containsMatchingElement(
<Child test="foo" setSeverityLevel={jest.fn}/>
)).toBe(true);
You forgot the space between test="foo" and setSeverityLevel={jest.fn()}.

Return null from a stateless component/"functional component"

I have a stateless functional component in React 0.14 that worked in React 0.13, but now returns the following error:
No render method found on the returned component instance: you may
have forgotten to define render, returned null/false from a
stateless component, or tried to render an element whose type is a
function that isn't a React component.
This is my component:
function ToggleDisplay(props) {
//should render a <noscript> per React's implementation
if(props.if === false) {
// return <noscript></noscript>; //do I have to do this manually now?
return null;
}
let style = {};
if(shouldHide(props)) {
style.display = 'none';
}
return (
<span style={style} {...props} />
);
}
Do I have to manually return a <noscript> now? Is there another way to return null in stateless component?
As of React 15.0, you can return null from a stateless functional component. (See #5355). No more having to return <noscript /> 🎉
The change that made this possible is that React removed support for component classes that don’t inherit from React.Component, meaning they can reliably differentiate between React components (classes that inherit React.Component) and functional stateless components. So the PR to enable the functionality just involved removing and simplifying the code that instantiates the components.
Looks like not, this is a technical constraint in Javascript. To support arrow functions and plain functions as "components" React needs to know if we can call new on them.
We can call new on everything if they're plain functions as long as
they return a ReactElement. However, that won't work for
null/false/string return values and we want to support those too. We
also can't call new on arrow functions. Likewise, we can't NOT call
new on classes.
Relevant GitHub Issue

Resources