But what is the difference between both of them ?
From this post it seems like there is no difference and it is just different way of writing.
Please provide an example to make the difference more clear.
All React Function Components are regular Javascript functions.
Not all regular Javascript functions are React Function Components.
Function components are just a signature for a specific function.
You can look at the Typescript definition to see exactly what that signature is:
interface FunctionComponent<P = {}> {
(props: PropsWithChildren<P>, context?: any): ReactElement<any, any> | null;
propTypes?: WeakValidationMap<P> | undefined;
contextTypes?: ValidationMap<any> | undefined;
defaultProps?: Partial<P> | undefined;
displayName?: string | undefined;
}
Reference: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react/v17/index.d.ts#L542
And PropsWithChildren is defined as:
type PropsWithChildren<P> = P & { children?: ReactNode | undefined };
Reference: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react/v17/index.d.ts#L822
The JSX parser will translate JSX and pass certain parameters to these functions.
JSX:
<CompOne someProperty="someValue"><CompTwo/></CompOne>
Equivalent to:
CompOne({someProperty: "someValue", children: CompTwo({})})
The signature is just letting you know how the JSX will be parsed, so you know how to access those parameters within your function.
The signature includes some additional info as well: the function should return a ReactElement or null, and it can have those four properties.
For example, I'm trying to log the someProperty value from CompOne:
<CompOne someProperty="someValue" someOtherProp="someOtherValue" />
CompOne(someProperty) {
console.log(someProperty); // logs {someProperty: "someValue", someOtherProp: "someOtherValue"}
return null;
}
This is incorrect, because I was not using the function as the Function Component signature describes. The JSX parser reads the properties into an object, and passes it as the first parameter to the function. Although the code will still execute, it is not what I intended to happen.
CompOne(props) {
console.log(props.someProperty); // logs "someValue"
return null;
}
This works as intended because I know the structure of a Function Component.
I have tried my best to keep it as simple as I can for your understanding:-
Javascript functions:-
function add(a, b) {
return a + b;
}
React functional component:-
import React from 'react';
const DisplayMessage = (props) => {
return <h1>{props.message}</h1>;
};
export default DisplayMessage;
USE:- JS functions are particular to do a thing. as you see in the example it will do the addition of two numbers only.while React functional components are used to define components in React that can be rendered to the UI. The display component will render the functional component.
DEFINITION:- JS functions are defined using the function keyword, while React functional components are defined using the const keyword and an arrow function.
PROPS:- We can pass and receive props to react functional components but not too regular JS functions.
STATE:- JS function doesn't have any state while React functional component when declared in classes will have the state.
RENDERING:- JS function doesn't render any change in the value.while React functional component re-render on every state or props change.
Related
I'm a beginner in JS/React and I am trying to wrap my head around the concept of when to use this.prop or just passing props down without this in React.
In some sources, the coder always uses this.prop while in others this seems to be unnecessary. Could anyone please clarify?
In this example, we are passing props username, authed, logout, and header from apps to hello. To do so, we use this.props. everytime we import.
However, in this example (React Native), we pass down term, onTermChange, and onTermSubmit from searchscreen to searchbar, without using this.props. Then I believe we re-defined our props in the TextInput of Search bar so its onEndEditing is the same as the onTermSubmit from the searchscreen.
I thought this.props may be a react syntax which became streamlined in React Native. However, I came across yet another example in React which does not use this.props:
You will use "this" when you have a class component. When you have a functional component there is no need , because you're not creating an instance of a class. All arguments passed to a class are stored into "this.props".
So in your second example and third example , you have functional components, which take the consts passed to them not as props, but as actual constants with their own names.
Hope this helps.
props is being used in both scenarios. You are just accessing props values differently. First example uses Class component. That means props is passed to children as this.props, where as second example uses stateless/ functional component, which means no this. And
const FunctionalComponent = (props) => {
const {name, onLogin} = props
......
}
is equivalent to
const FunctionalComponent = ({name, onLogin}) => {
.....
}
due to Object Destructuring, hence you are not seeing explicit use of props in second example.
It's not a React thing but a JavaScript thing.
Classes - Here you need to access the state and props using the this keyword.
Functions - Here you don't need to use this in React. The argument to your function component here are props so you can directly use props.something and not this.props.something.
In your Searchbar component:-
const Searchbar = ({term,onTermSubmit,onTermChange}) means that the properties
term,onTermSubmit and onTermChange are being destructured from the props object and so can now be used directly. You don't need to access them like props.term anymore. They can directly be accessed like term wherever you want them to be.
I have a constants file constants.ts:
export const C0NST = "constant";
I access it in a service some.service.ts like so:
import { C0NST } from './constants';
console.log(C0NST); // "constant"
However, when I access it in a component template:
some.component.ts:
import { C0NST } from './constants';
some.component.html:
{{ C0NST }} <!-- Outputs nothing -->
However defining a member in the component class works:
some.component.ts
public const constant = C0NST;
some.component.html
{{ constant }} <!-- constant -->
I don't understand why I was able to access the imported constant directly in the service class but not in the component template even though I imported it in the component class.
In Angular2, the template can only access fields and methods of the component class. Everything else is off-limits. This includes things which are visible to the component class.
The way to go around this is to have a field inside the component, which just references the constant, and use that instead.
It's one limitation of the design, but perhaps you should think a bit more about why you need a constant in the template in the first place. Usually these things are used by components themselves, or services, but not the template.
Since in the Component's template you can only use attributes of the Component's class, you can't directly use any external constants (or external variables).
The most elegant way that I've found so far is the following:
import { MY_CONSTANT } from '../constants';
#Component({
// ...
})
export class MyTestComponent implements OnInit {
readonly MY_CONSTANT = MY_CONSTANT;
// ...
}
which basically just creates a new attribute MY_CONSTANT inside the component class. Using readonly we make sure that the new attribute cannot be modified.
Doing so, in your template you can now use:
{{ MY_CONSTANT }}
The scope of Angular2 template bindings is the component instance. Only what's accessible there can be used in bindings.
You can make it available like
class MyComponent {
myConst = CONST;
}
{{myConst}}
There are two best directions in my opinion:
Wrapping constants as internal component property
enum.ts
export enum stateEnum {
'DOING' = 0,
'DONE',
'FAILED'
}
component.ts
import { stateEnum } from './enum'
export class EnumUserClass {
readonly stateEnum : typeof stateEnum = stateEnum ;
}
Example uses enum, but this can be any type of defined constant. typeof operator gives you all of benefits of TypeScript typing features. You can use then this variable directly in templates:
component.html
<p>{{stateEnum.DOING}}<p>
This solution is less efficient in memory usage context, because you are basically duplicating data (or references to constants) in each component you wish to use it. Beside that, syntax
readonly constData: typeof constData = constData
in my opinion introduce a lot of syntax noise and may be confusing to newcommers
Wrapping external constant in component function
Second option is to wrap your external variable/constant with component function and use that function on template:
enum.ts
export enum stateEnum {
'DOING' = 0,
'DONE',
'FAILED'
}
component.ts
import { stateEnum } from './enum'
export class EnumUserClass {
getEnumString(idx) {
return stateEnum[stateEnum[idx]];
}
}
component.html
<p>{{getEnumString(1)}}</p>
Good thing is that data is not duplicated in controller but other major downside occur. According to Angular team, usage of functions in templates is not recommended due to change detection mechanism, which works way less efficient in case of functions returning values to templates: change detection have no idea does value return by a function has changed, so it will be called way often than needed (and assuming you returning const from it, it's actually needed only once, when populating template view. It may be just a bit efficiency killing to your application (if you are lucky) or it may totally break it down if function resolves with Observable for instance, and you use async pipe to subscribe to results. You can refer to my short article on that HERE
You can create a BaseComponent , it is a place where you should create your constant instances and then you can create your FooComponent extends BaseComponent and you can use your constants.
I am trying to figure out a way to be able to memoize React components by specifying particular props.
For instance, if you use React.memo — it memoizes the component based on all props.
What I am trying to achieve is being able to pass particular props as a dependency to a util (say, SuperMemo) and the component will be memoized based on those props. The approach is very similar to what recompose — compose the component before export.
Here's an example code
import React from "react";
const isFunction = value =>
value &&
(Object.prototype.toString.call(value) === "[object Function]" ||
"function" === typeof value ||
value instanceof Function);
export const memo = (Comp, resolver) => {
if (isFunction(resolver)) {
const Memoized = props => {
const deps = resolver(props);
if (deps && deps.length) {
// eslint-disable-next-line react-hooks/rules-of-hooks
return React.useCallback(React.createElement(Comp, props), deps);
}
return React.createElement(Comp, props);
};
Memoized.displayName = `memoized(${Comp.name})`;
return Memoized;
}
return React.memo(Comp);
};
export default memo;
Here is how it will be used to compose components
import Todo from "./Todo";
import memo from "../memo";
export default memo(Todo, props => [props.text]);
I have a working codesandbox here — memo-deps
This is what I have observed —
I should not use React.useCallback or any hook inside a conditional statement because React needs to know the order in which hooks are invoked and using it inside a conditional may mess up the order during runtime
But React.useCallback works pretty neat in a conditional for my case as I know the order will remain the same during runtime
I am not using the hook inside the conditional statement during render, instead I am composing the component during export conditionally
I am thinking about React components as plain JavaScript functions and trying to memoize it like how I would memoize a regular JavaScript function
I could easily replace React.useCallback with lodash.memoize and the end result will be pretty much the same
I don't want to use an external library like lodash.memoize or build a custom implementation of memoization while React.useCallback pretty much does the work for me
This is where I am not sure what's happening (these are my questions) —
React components are not really vanilla JavaScript functions and I cannot memoize them with lodash.memoize
lodash.memoize and React.useCallback are not the same when I try to memoize a React component
React executes the function before figuring out the render even when React.memo is used (maybe to check prevProps vs newProps?)
Is my implementation okay even though it breaks the rules of React? (use hook in a conditional statement)
How else can I memoize a React.createElement if not for React.useCallback?
The reason as to why I might want to do this —
I don't want to memoize handlers (closure with a value and event) every time I pass them to a component wrapped in React.memo. I want to be able to declaratively write memoize dependencies for components.
React.memo accepts a function as the second parameter to do a custom props comparison.
By default it will only shallowly compare complex objects in the props
object. If you want control over the comparison, you can also provide
a custom comparison function as the second argument.
You can use that in your util function like this :
export const memoWithSecondParam = (Comp, deps = []) => {
return React.memo(Comp, (prevProps, nextProps) => {
return deps.every(d => prevProps[d] === nextProps[d])
});
};
And call it like this :
export default memoWithSecondParam(Todo, ["text"]);
I've recently started to use Typescript in my React projects and I'm struggling to understand generics inside of function declarations and the Redux connect function.
For example if I have the following code
interface WidgetStateProps extends BasicConfiguration {
filters: Filter[]
}
class Widget extends React.Component<WidgetComponentProps, {}> {
// my component
}
Now to my understanding, by declaring the generic, <WidgetComponentProps, {}> here, we have told typescript that we expect that the props our Widget component will receive will have the properties defined in WidgetStateProps and BasicConfiguration. Correct?
Great now moving onto an example of typing the connect function which is not necessarly in the same component as the one above.
export default connect<ModalStateProps, ModalDispatchProps, ModalOwnProps>(mapStateToProps, mapDispatchToProps)(Modal);
In this connect function we have declared 3 generics. I'm confused on how these are typing mapStateToProps and mapDispatchTopProps when both of these return a function. Furthermore, what is ModalOwnProps typing?
The final things I'm having trouble understand revolves around using connect with higher order functions. Say I have the following connect function
export default function composeWidget<T extends WidgetStateProps, P extends WidgetDispatchProps, Q extends WidgetOwnProps>(Component, mapStateToProps, mapDispatchToProps = undefined, mergeProps = undefined) {
// some more code
return connect<T, P, Q>(wrappedMapStateToProps, wrappedMapDispatchToProps, mergeProps)(getComposedWidgetComponent(Component));
}
This is where everything starts to get really fuzzy. From this it seems that my first point is wrong. How could T extends WidgetStateProps define the shape of the first argument in the function which is Component when it clearly defines the second one.
Another confusion is what advantage do we gain by extending these various interfaces such as WidgetStateProps?
So i love this React thingy, and we have this so called 'stateless' functions to help us build a 'dumb' component. Now i want to create a class that produce a stateless function. Why you may ask, well i love the idea of inheritance and wanting to 'extend' my stateless function basic capability, said i want to add a helper function as a statics that binds to the function itself.
I ended up with this code
class Stateless {
constructor() {
return this.render.bind(this)
}
nanny() {
// do something
}
render(props) {
// yeay! a stateless function!
// plus i can access nanny by using this.nanny()
}
}
And when i extend it, i can see that the inheritance is working well.
BUT, if then i initialize the class:
const stateless = new Stateless()
Why can't i access stateless.nanny even tho inside the render function i can see that this.nanny is accessible? Where does the nanny lives? Does it binded to the render function?
EG:
class Stateless {
constructor() {
return this.render.bind(this)
}
nanny() {
console.log('foo')
return true
}
render(props) {
console.log(this.nanny()) // -> returns 'foo'
return 'JSX'
// this should return a JSX
}
}
const stateless = new Stateless() // -> stateless IS a function
stateless()
// 'foo'
// true
// JSX
stateless.nanny
// undefined
While clearly inside render when i called this, there is nanny there. But when i
refer it outside, the nanny is gone. I thought nanny should be a static property of the stateless, right?
If you are returning object from constructor - new will return that object instead of the instance of the class being constructed (more info).
Therefore line
const stateless = new Stateless()
will assign to stateless variable result of this.render.bind(this) - that is reference to method (function) of Stateless class, that is not an instance of Stateless. Therefore stateless.nanny makes no sense - as function render does not have such property defined. On the other hand calling bound render function directly - produce the expected result.
All in all - i strongly do not recommend you to return anything from constructor (unless you are dealing with some really weird requirements like controlling number of instances and such). It makes code hard to understand and maintain.
Your example should work if you remove this.render.bind(this) from your constructor.
It should also work, if you just remove return from the constructor:
constructor() {
this.render.bind(this)
}
However, you might actually be looking to create a higher order component that can enhance the component that it wraps.
Your higher order component is a function that returns a class that renders the component that it passed to it:
import React from 'react'
function HigherOrderComponent(WrappedComponent) {
return class Enhancer extends React.Component {
constructor(props) {
super(props)
}
exampleFunc() {
// Code here
}
render() {
return <WrappedComponent exampleprop={ this.exampleFunc } />
}
}
}
export default HigherOrderComponent
Then you can import HigherOrderComponent into your stateless dumb component file and wrap the export:
import React from 'react'
import HigherOrderComponent from './HigherOrderComponent'
const DumbComponent = (props) => {
// Return JSX
// You can use props.exampleprop
}
export default HigherOrderComponent(DumbComponent)
Here are some articles that you can read on higher order components:
https://facebook.github.io/react/docs/higher-order-components.html
https://medium.com/#franleplant/react-higher-order-components-in-depth-cf9032ee6c3e