I have two components in first component I created the function "onClick" with difficult logic, the function "onClick" use API and reducer, also use other functions. I need use function "onClick" in second component, but I don't how to do this better. Can you help me please?
import React, { useEffect } from 'react';
import {Switch, Route, Link, Redirect} from 'react-router-dom';
import PageComponent_1 from '../page-component-1';
import PageComponent_2 from '../page-component-2';
const Application: React.FunctionComponent = () => {
return (
<div>
<div>
<hr />
<nav>
<ul>
<li>
<Link to="/PageComponent_1">PageComponent_1</Link>
</li>
<li>
<Link to="/PageComponent_2">PageComponent_2</Link>
</li>
</ul>
</nav>
<hr />
<Switch>
<Route exact path={ "/PageComponent_1" } component={ PageComponent_1 } />
<Route exact path={ "/PageComponent_2" } component={ PageComponent_2 } />
<Redirect to="/"/>
</Switch>
</div>
</div>
);
};
export default Application;
first component
import React, {useState} from 'react';
type Props = {
}
type State = {
field_1: string
};
const PageComponent_1: React.FunctionComponent<Props> = () => {
const [state, changeState] = useState<State>(
{
field_1: '',
},
);
const onClick = (e:any, feldName:string) =>{
//here is difficult logic
changeState((state) => ({
...state,
[feldName]: 'TEST'
}));
}
return (
<div className="">
PageComponent_1
<div onClick={(e:any)=>onClick(e, 'field_1')}>
ClickMe
</div>
</div>
);
};
export default React.memo(PageComponent_1);
second component
import React, {useState} from 'react';
type Props = {
}
type State = {
field_2: string
};
const PageComponent_2: React.FunctionComponent<Props> = () => {
const [state, changeState] = useState<State>(
{
field_2: '',
},
);
return (
<div className="">
PageComponent_2
</div>
);
};
export default React.memo(PageComponent_2);
You can create the function outside of any component, having it accept the type of the state object as a type parameter and the state setter function to use (changeState in your code) as a parameter:
const onClick = <StateType,>(
e: any,
fieldName: keyof StateType,
changeState: React.Dispatch<React.SetStateAction<StateType>>
) => {
//here is difficult logic
changeState((state) => ({
...state,
[fieldName]: "TEST"
}));
};
Here's how you use it in your current component:
const PageComponent_1: React.FunctionComponent<Props> = () => {
const [state, changeState] = useState<State>(
{
field_1: "",
},
);
const onClickField1 = useCallback((e: any) => onClick(e, "field_1", changeState), []);
return (
<div className="">
PageComponent_1
<div onClick={onClickField1}>
ClickMe
</div>
</div>
);
};
Some key bits there:
onClick needs to be generic so the state type it's working with comes from where it's used; that's the StateType type parameter.fieldName is keyof StateType so we can use it to set the property in a typesafe manner.changeState (more typically called setState) uses the React type React.Dispatch<React.SetStateAction<T>> where T is a type parameter for the type of the state item (in our case, StateType). (If you ever wonder about the types of things like that, in any decent IDE you can just hover the mouse over the state setter, etc., and the IDE will show you the type.)