React - Get displayName of functional component inside the component? - reactjs

Is it possible to get the name of a functional component inside it?
Something like:
function CarWasher(props) {
const handleOnPress = () => {
console.log(this.displayName); // <-- Something like this displayName
}
return ...JSX;
};
CarWasher.displayName = "CarWasher";

You can reference the .name property of the function.
function CarWasher(props) {
const handleOnPress = () => {
console.log(CarWasher.name);
}
handleOnPress();
};
CarWasher();
If you're worried about accidentally making a typo when referencing one of the above variables, consider using TypeScript or at least the no-undef ESLint rule.

Also, with displayName:
function MemoizedCarWasher(props) {
const handleOnPress = () => {
console.log(MemoizedCarWasher.displayName);
}
handleOnPress();
};
MemoizedCarWasher.displayName = "CarWasher";
MemoizedCarWasher();

Related

Cannot update a component while rendering a different Component - ReactJS

I know lots of developers had similar kinds of issues in the past like this. I went through most of them, but couldn't crack the issue.
I am trying to update the cart Context counter value. Following is the code(store/userCartContext.js file)
import React, { createContext, useState } from "react";
const UserCartContext = createContext({
userCartCTX: [],
userCartAddCTX: () => {},
userCartLength: 0
});
export function UserCartContextProvider(props) {
const [userCartStore, setUserCartStore] = useState([]);
const addCartProduct = (value) => {
setUserCartStore((prevState) => {
return [...prevState, value];
});
};
const userCartCounterUpdate = (id, value) => {
console.log("hello dolly");
// setTimeout(() => {
setUserCartStore((prevState) => {
return prevState.map((item) => {
if (item.id === id) {
return { ...item, productCount: value };
}
return item;
});
});
// }, 50);
};
const context = {
userCartCTX: userCartStore,
userCartAddCTX: addCartProduct,
userCartLength: userCartStore.length,
userCartCounterUpdateCTX: userCartCounterUpdate
};
return (
<UserCartContext.Provider value={context}>
{props.children}
</UserCartContext.Provider>
);
}
export default UserCartContext;
Here I have commented out the setTimeout function. If I use setTimeout, it works perfectly. But I am not sure whether it's the correct way.
In cartItemEach.js file I use the following code to update the context
const counterChangeHandler = (value) => {
let counterVal = value;
userCartBlockCTX.userCartCounterUpdateCTX(props.details.id, counterVal);
};
CodeSandBox Link: https://codesandbox.io/s/react-learnable-one-1z5td
Issue happens when I update the counter inside the CART popup. If you update the counter only once, there won't be any error. But when you change the counter more than once this error pops up inside the console. Even though this error arises, it's not affecting the overall code. The updated counter value gets stored inside the state in Context.
TIL that you cannot call a setState function from within a function passed into another setState function. Within a function passed into a setState function, you should just focus on changing that state. You can use useEffect to cause that state change to trigger another state change.
Here is one way to rewrite the Counter class to avoid the warning you're getting:
const decrementHandler = () => {
setNumber((prevState) => {
if (prevState === 0) {
return 0;
}
return prevState - 1;
});
};
const incrementHandler = () => {
setNumber((prevState) => {
return prevState + 1;
});
};
useEffect(() => {
props.onCounterChange(props.currentCounterVal);
}, [props.currentCounterVal]);
// or [props.onCounterChange, props.currentCounterVal] if onCounterChange can change
It's unclear to me whether the useEffect needs to be inside the Counter class though; you could potentially move the useEffect outside to the parent, given that both the current value and callback are provided by the parent. But that's up to you and exactly what you're trying to accomplish.

Convert react class to react function

Hi so I have two files and i want to convert one of them into a react functional component. The first one is PuzzleGrid and it will call the function Grid.getMatrix()
export const PuzzleGrid = () => {
const newMatrix = GridLib.getMatrix();
}
and the next is Gridlib which is a react class :
export class GridLib {
static getMatrix() {
return Array(6).fill(Array(6).fill(0));
}
}
I want to be able to convert the class into a function, this is what i have, however i am getting an error. does anyone understand why?
export const GridLib = () => {
GridLib.getMatrix = {
Array(6).fill(Array(6).fill(0));
}
}
You can simply return the results of the getMatrix method:
export const GridLib = () => {
return Array(6).fill(Array(6).fill(0));
}
However, this will cause a problem for your PuzzleGrid component, as it depends on GridLib having a getMatrix method. You would have to simply have PuzzleGrid return a GridLib for it to work as such:
export const PuzzleGrid = () => {
return <GridLib />
}
However this pattern is a bit silly and repetetive. I feel like there must be more going on to your question, but you may have reduced it down too much and stripped away some important details. What is the larger context of this issue?
Just use a function properties to declare a "static method"
export const GridLib = () => {
return <View/> ;
}
GridLib.getMatrix = () => {
return Array(6).fill(Array(6).fill(0));
}

Reactjs hook that uses other hooks

I needed to create a custom hook which is supposed to contain all the handlers that will be used everywhere in my page. My requirements were;
Handlers are supposed to be accessible from all the components in the page
Handlers should be able to use other hooks, like useContext
So, created a useHandlers hook sandbox
However, couldn't make the LogHandler accessible from the page, receving LogHandler is not a function
Any idea?
The issue why you're getting LogHandler is not a function is because it's undefined and it doesn't get initialized until HandlerComp gets called:
export const userHandlers = (): IUseHandlers => {
// initialization skipped, so `LogHandler` is undefined
let LogHandler: () => void;
const HandlersComp: React.FunctionComponent<HandlersProps> = (
props: HandlersProps
) => {
// initialized here, but that's after `HandlersComp` gets caled
LogHandler = () => {
console.log("Hi from LogHandler");
};
return <></>;
};
return { HandlersComp, LogHandler };
}
I suggest you move the initialization step from HandlersComp like so:
export const useHandlers = (): IUseHandlers => {
const LogHandler: () => void = () => {
console.log("Hi from LogHandler");
};
const HandlersComp: React.FunctionComponent<HandlersProps> = (
props: HandlersProps
) => {
LogHandler()
return <></>;
};
return { HandlersComp, LogHandler };
};
Some notes:
HandlersComp looks like it should be a separate and reusable component, rather than a hook
LogHandler also looks more like a utility function, rather than a hook
LogHandler shouldn't be using PascalCase for naming as that should be "reserved" for React components; HandlersComp is fine, since it looks like it's a component

React TypeScript - passing a callback function

The following code would have worked happily in JavaScript. I am using React+TypeScript, hence this is a JSX file:
Calling component:
<FiltersPanel onFiltersChanged={() => { console.log('I was called') }} />
Inner Component:
const FiltersPanel = (onFiltersChanged) => {
const handleFiltersChange = () => {
onFiltersChanged(); /* I am getting `TypeError: onFiltersChanged is not a function` */
};
return (<div onClick={handleFiltersChange}/> );
};
export default FiltersPanel;
Why is TypeScript complaining that it cannot find the function, while the function is certainly passed as a prop.
You passed the function as a props so you should receive it to your component as a props like this
const FiltersPanel = (props) => { }
then use it like this
props.onFiltersChanged()
OR you can use destructuring like this
const FiltersPanel = ({onFiltersChanged}) => { }
so you can use it without the props object like this
onFiltersChanged()

Should I use useMemo in hooks?

I created useBanner hooks
const useBanner = (array, yardage) => {
const [bannArr, setBannArr] = useState(array.slice(0, yardage));
const [bannListIndex, setBannIndex] = useState(1);
return {
....
};
};
Am I doing the right thing and the props throw in useState.
It’s permissible to use useBanner.
const Banner= ({
array,
yardage
}) => {
const { bannForth, bannBeck, bannArr } = useBanner(array, yardage);
return (
...
);
};
when props will change here.
Will change the state in useBanner.
or is it considered anti-patterns I have to write all this in useMemo
const useBanner = (array, yardage) => {
const [bannArr, setBannArr] = useState([]);
const [bannListIndex, setBannIndex] = useState(1);
useMemo(() => {
setBannArr(array.slice(0, yardage));
setBannIndex(1);
}, [array, yardage]);
return {
....
};
};
Yes, custom hooks are possible in React. Here is separate document discussing custom hooks.
But exactly you sample may require additional code depending on what is your final goal.
If you want initialize state only once, when component Banner is first created, you can just do as in your first sample
const Banner= ({
array,
yardage
}) => {
const { bannForth, bannBeck, bannArr } = useBanner(array, yardage);
return (
...
);
};
This will work perfectly. But if props array and yardage will change, this will not be reflected in component. So props will be used only once as initial values and then will not be used in useBanner even if changed (And it doesn't matter whether you'll use useBanner or useState directly). This answer highlight this.
If you want to update inital values on each props change, you can go with useEffect like below
const Banner= ({
array,
yardage
}) => {
const { bannForth, bannBeck, bannArr, setBannArr } = useBanner(array, yardage);
useEffect (() => {
// setBannArr should also be returned from useBanner. Or bannArr should be changed with any other suitable function returned from useBanner.
setBannArr(array.slice(0, yardage));
}, [array, yardage, setBannArr])
return (
...
);
};
In this case Banner component can control state itself and when parent component change props, state in Banner component will be reset to new props.
Here is small sample to showcase second option.

Resources