Functions in stateless components?
First thing to note is that stateless functional components cannot have methods, you shouldn't count on calling update
or draw
on a rendered Ball
if it is a stateless functional component.
In most cases you should declare the functions outside of the component function so you declare them only once and always reuse the same reference. When you declare the function inside, every time the component is rendered the function will be defined again.
There are cases in which you will need to define a function inside the component to, for example, assign it as an event handler that behaves differently based on the properties of the component. But still you could define the function outside Ball
and bind it with the properties, making the code much cleaner and making the update
or draw
functions reusable.
// You can use update somewhere else
const update (propX, a, b) => { ... };
const Ball = props => (
<Something onClick={update.bind(null, props.x)} />
);
If you're using hooks, you can use useCallback
to ensure the function is only redefined when one of its dependencies (props.x
in this case) changes:
const Ball = props => {
const onClick = useCallback((a, b) => {
// do something with a, b and props.x
}, [props.x]);
return (
<Something onClick={onClick} />
);
}
This is the wrong way:
const Ball = props => {
function update(a, b) {
// props.x is visible here
}
return (
<Something onClick={update} />
);
}
When using useCallback
, defining the update
function in the useCallback
hook itself our outside the component becomes a design decision more than anything, you should take into account if you're going to reuse update
and/or if you need to access the scope of the component's closure to, for example, read/write to the state. Personally I choose to define it inside the component by default and make it reusable only if the need arises, to prevent over-engineering from the start. On top of that reusing application logic is better done with more specific hooks, leaving components for presentational purposes. Defining the function outside the component while using hooks really depends on the grade of decoupling from React you want for your application logic.
We can have functions inside stateless functional components, below is the example:
const Action = () => {
function handlePick(){
alert("test");
}
return (
<div>
<input type="button" onClick={handlePick} value="What you want to do ?" />
</div>
);
}
But, it's not a good practice as function handlePick()
will be defined every time when the component is called.
We can use the React hook useCallback
as below in a functional component:
const home = (props) => {
const { small, img } = props
const [currentInd, setCurrentInd] = useState(0);
const imgArrayLength = img.length - 1;
useEffect(() => {
let id = setInterval(() => {
if (currentInd < imgArrayLength) {
setCurrentInd(currentInd => currentInd + 1)
}
else {
setCurrentInd(0)
}
}, 5000);
return () => clearInterval(id);
}, [currentInd]);
const onLeftClickHandler = useCallback(
() => {
if (currentInd === 0) {
}
else {
setCurrentInd(currentInd => currentInd - 1)
}
},
[currentInd],
);
const onRightClickHandler = useCallback(
() => {
if (currentInd < imgArrayLength) {
setCurrentInd(currentInd => currentInd + 1)
}
else {
}
},
[currentInd],
);
return (
<Wrapper img={img[currentInd]}>
<LeftSliderArrow className={currentInd > 0 ? "red" : 'no-red'} onClick={onLeftClickHandler}>
<img src={Icon_dir + "chevron_left_light.png"}></img>
</LeftSliderArrow>
<RightSliderArrow className={currentInd < imgArrayLength ? "red" : 'no-red'} onClick={onRightClickHandler}>
<img src={Icon_dir + "chevron_right_light.png"}></img>
</RightSliderArrow>
</Wrapper>);
}
export default home;
I'm getting 'img' from it's parent and that is an array.