Test React stateless private function - javascript

My react component is like this i am rendering part of component using getMenuItems method.
const TransactionListFilter = (props) => {
const getMenuItems = () => filterCriteriaItems.map((data) =>
<MenuItem value={data.valu} name={data.name} >{data.name}</MenuItem>,
);
return (
<Dropdown
className="Transaction-List-Filter-container-dropdown"
selectMode="single"
defaultText="See All"
onMenuItemClick={handleFilterChange}
>
<Menu>
{
getMenuItems()
}
</Menu>
</Dropdown>
);
};
How i can test method getMenuItems any Idea?

The problem is that you are hiding the method getMenuItems to be an internal working of the TransactionListFilter function. Are you sure you want to test it? As soon as you refactor the TransactionListFilter method, your test will break. As far as I see, you have 2 options:
Refactor to a class:
class TransactionListFilter {
getMenuItems(){
return filterCriteriaItems.map((data) =>
<MenuItem value={data.valu} name={data.name}>{data.name}</MenuItem>,
);
}
render() {
return (
<Dropdown
className="Transaction-List-Filter-container-dropdown"
selectMode="single"
defaultText="See All"
onMenuItemClick={handleFilterChange}
>
<Menu>
{
this.getMenuItems()
}
</Menu>
</Dropdown>
);
}
};
Hacky translation of the function (e.g. converting the function to a string, then parsing the string up until the return, and passing the result to the Function constructor). That would look something like this: (at your own risk)
const getMenuItems = new Function('', `${TransactionListFilter.toString().match(/\getMenuItems.*=.*=>(.*)\)/s)[1]};`)

Related

React using multiple dynamic contexts for one component

I made a little utility function(HOC) that can provide the value of a context to a given component
export function withContext<CT>(Component: any) {
return function ContextPass(Context: React.Context<CT>) {
return function Inner(props: any) {
return (
<>
<Context.Consumer>
{
(values) => (
<>
{React.createElement(Component, { ...props, ...values })}
</>
)
}
</Context.Consumer>
</>
);
}
}
}
where I use it like this:
class DesignerHomeLayout extends React.Component{
...
}
export default withContext<ProfileContextType>(
withStyles(styles)(DesignerHomeLayout)
)(ProfileContext)
It's working fine, but my problems is where I want to wrap the component with many Contexts, I know I can wrap again with withContext utility, but I want to make a utility that can take a component and an array of contexts and provide all contexts values to that one component
So far I've made something like this, but it still not working for me
function makeWrapperContext(Context: any, Component: any) {
return function Inner(props: any) {
return (
<>
<Context.Consumer>
{
(values: any) => (
<>
{React.createElement(Component, { ...props, ...values })}
</>
)
}
</Context.Consumer>
</>
);
}
}
export function withContexts({
component, contexts
}: { component: any, contexts: React.Context<any>[] }) {
return contexts.reduce(makeWrapperContext, component);
}
where the desired usage would be
export default withContexts({
component: withStyles(styles)(DesignerHomeLayout),
contexts: [ProfileContext, LabelsContext]
});
I know it might be close to what the solution is, but I'm not sure about it, my biggest challenge is to pass the component parameter to the reduce function, I know it will not work because when the utility function is invoked, the <component.Consumer> will not exist.
I'm open to any edits to this code, or any new solution you have.
One important note: I can't use functional components with hooks within my project, but I'll welcome any hooks based solution, because that will still benefit me and others in future.

Send onClick function as props to a component in React with Typescript

I'm new to Typescript and I have to write a parent component that sends as props onClick to the child component where is a button that triggers the functionality of onClick when clicked.
Here is the code:
export function ParentComponent(props: ParentComponentProps) {
const [isOpened, toggleModal] = useToggle(false);
// useToggle is a custom hook that toggles a boolean
...
const onClick = () => {
toggleModal();
}
return (
<ChildComponent onClick={onClick} />
);
}
For the child component I don't know how to define the interface, what should be put here?
export interface ChildComponentProps {
onClick: <unknown>(); // what to add here?
}
And here is the child component:
export function ChildComponent({onClick}: ChildComponentProps) {
...
return (
<div>
...
<ButtonComponent
onClick={() => onClick()}
...
/>
...
);
}
Any ideas what to add to the interface or if there should be any other changes to be Typescript correct?
For functions like onClick, you have to describe input arugments and output or just write Function (although for better type checking you shouldn't just write Function).
So something like this:
onClick: () => void
If for example your function gets a number and returns a string, you should write it like this:
onClick: (n: number) => string
Parent Component:
interface OnClickIdInterface {
(): void,
}
export interface parentPropsInterface {
onClick?: OnGetIdInterface;
}
render() {
return <ChildComponent onClick={(id) => this.onClick(id)}/>
}
Child Component:
const HomePresentation: React.FunctionComponent<parentPropsInterface> = ({onClick}) => {
return (
<div onClick={()=>onClick()}>
some content
</div>
)
}
Following code should work. But it depends on ButtonComponent. Used React.MouseEventHandler<T = Element> as type.
export interface ChildComponentProps {
onClick: React.MouseEventHandler<ButtonComponent>
}
export function ChildComponent({onClick}: ChildComponentProps) {
...
return (
<div>
...
<ButtonComponent
onClick={() => onClick()}
...
/>
...
);
}
Please notify me if this is incorrect.

How to make data accessible to subchild component using React useContext [duplicate]

I have a component that renders:
<View>
<SomeContext.Provider value={state}>
{props.children}
</SomeContext.Provider>
</View>
I don't understand how to create a method accessible in the following way:
<View>
<SomeContext.Provider>
{(method) =>
<Button
title={"Magic"}
onPress={() => {
method()
}}
></Button>
}
</SomeContext.Provider>
</View>
Consumer Component
You need to consume a context through a Context.Consumer that is a direct descendent of the the relevant Provider. The docs have decent examples, though they mix class-based and functional components. Updating Context from a Nested Component
Sandbox: https://codesandbox.io/s/react-context-consumer-passing-method-to-nested-child-forked-u0bi8
const initData = {
data: { a: "Text from Context", b: "2" },
method: () => {
console.log("Method called.");
}
};
const SomeContext = React.createContext();
export default function App() {
return (
<SomeContext.Provider value={initData}>
<Content />
</SomeContext.Provider>
);
}
function Content() {
return (
<div>
<SomeButton />
</div>
);
}
function SomeButton() {
return (
<SomeContext.Consumer>
{({ data, method }) => <button onClick={method}>{data.a}</button>}
</SomeContext.Consumer>
);
}
useContext Hook
The useContext hook is also available, and possibly provides a more familiar pattern. The Consumer of the context still needs to be a descendant of the Provider, but it is accessed via an hook rather than through a Consumer component.
Sandbox: https://codesandbox.io/s/react-context-passing-method-to-nested-child-1fcno
const initData = {
data: { a: "Text from Context", b: "2" },
method: () => {
console.log("Method called.");
}
};
const SomeContext = React.createContext();
export default function App() {
return (
<SomeContext.Provider value={initData}>
<Toolbar />
</SomeContext.Provider>
);
}
function Toolbar(props) {
return (
<div>
<SomeButton />
</div>
);
}
function SomeButton() {
const { data, method } = React.useContext(SomeContext);
return <button onClick={method}>{data.a}</button>;
}
The Context counsumer docs actually tells you everything you need to know:
A React component that subscribes to context changes. This lets you subscribe to a context within a function component.
Requires a function as a child. The function receives the current context value and returns a React node. The value argument passed to the function will be equal to the value prop of the closest Provider for this context above in the tree. If there is no Provider for this context above, the value argument will be equal to the defaultValue that was passed to createContext().
So, in your example you need to pass the method you want to the provider:
const method = () => {};
<View>
<SomeContext.Provider value={{ method }}>
{props.children}
</SomeContext.Provider>
</View>
And then in the Consumer you can call it like this:
<View>
<SomeContext.Consumer>
// using destructuring here,
// so its ({ method }) instead of (method)
{({ method }) =>
<Button
title={"Magic"}
onPress={() => method()} />
}
</SomeContext.Consumer>
</View>
Also, it's important that the consumer component is inside the provider.

How to pass two functions to onClick event in react

I want to pass two functions to onClick event which is handleSubmit and handleDelete to the HomePage.js from the HomeItem.js
Here is my Error:
No duplicate props allowed react/jsx-no-duplicate-props.
Here is my HomePage.js:
const HomePage = props => {
const tvshow = props.item;
let res;
if (tvshow.length > 0) {
res = tvshow.map(res=> (
<Content item={res} onClick={props.onClick}/>
));
}
return (
<div>
<Container>
<Row>{res}</Row>
</Container>
</div>
);
};
export default HomePage;
Here is my HomeItem.js:
const HomeItem = props => {
function handleSubmit() {
props.onClick({
name: props.item.name,
id: props.item.id
});
}
function handleName() {
props.onClick({
name: props.item.name
});
}
<Button onClick={handleSubmit}></Button>
<Button onClick={handleName}></Button>
Here is my App.js:
handleSubmit(newFavorite) {}
handleName(newFavorite) {}
render() {
<Route
exact
path="/"
render={() => (
<HomePage
item={this.state.SaveFavorite}
onClick={this.handleSubmit}
onClick={this.handleName}
/>
)}
/>
}
So my question is how to put 2 onClick function to the Hompage.js
How about this:
<HomePage
item={this.state.SaveFavorite}
onClick={(favorite)=>{
this.handleSubmit(favorite);
this.handleName(favorite);
}
}
/>
This assumes your goal is to call both functions one at a time. If they should be called in different situations give one function a different name, eg onSubmit or onNameChange.
Try This:
<HomePage
item={this.state.SaveFavorite}
onClick={(newFavorite) => this.handleSubmit(newFavorite);this.handleName(newFavorite)}
/>
you can pass multiple functions to events in react, let say changeEvent, to do follow those steps.
1- create your function two or the number of function you like.
2- create an object that contains those functions
3- pass the object as a props to where it would be consumed
4- choose the correspondant function to each form or whatever you need.
here is an example, this sample is with typescript.
const onChangeFunctions = {
onChangeForm1: handleChangeForm1,
onChangeForm2: handleChangeForm2,
};
<MainForm
onChange={onChangeFunctions} // here is your function
datas={yourData}
otherProps={otherProps}
/>
Now you use the fucntion on the child components
interface PropsFrom {
model1: Model1;
model2: Model2;
onChange: any;
}
export default function ProductForm(props: PropsForm) {
return (
<Container maxWidth="lg">
<Grid item md={6}>
<FormOne
model={props.model1} // the model that bind your form
onChange={props.onChange.onChangeForm1} // here you can use your first function
/>
</Grid>
<Grid item md={6}>
<FormTwo
model={props.model2} // the model that bind your form
onChange={props.onChange.onChangeForm2} // here you can use your second function
/>
</Grid>
</Grid>
</Container>
for javascript just pass the functions as props and delete the interface from the child components.

React/material ui raisedbutton executing onTouchTap on init

I am using react/redux/material ui and normally through out my website the components work fine. One 1 page there is something very very wierd going on.
I create a component like this:
class MyOwnComponent extends Component {
doSomething = (id) => {
alert('doSomething: id = ' + id )
}
render() {
return (
<RaisedButton secondary={true} label={'My label'} onTouchTap={this.doSomething(id)}/>
)
}
}
I have a raisedbutton from material ui and put it in the render method.
The thing is that when the page loads with the component in it the doSomething method is called. Even though it is only called in the onTouchTap in raisedbutton. Almost as if a bug in the raisedbutton is calling the onTouchTap method immediately instead when the button is clicked.
Does any body have a explanation for this really strange behaviour?
Thanks
You are giving to onTouchTap void, because that's what this.doSomething(id) returns .
this.doSomething(id)
is executed the firs time MyOwnComponent is rendered.
Instead you should do this :
class MyOwnComponent extends Component {
doSomething = () => {
const {id} = this.props.object;
alert('doSomething: id = ' + id )
}
render() {
return (
<RaisedButton secondary={true} label={'My label'} onTouchTap={this.doSomething}/>
)
}
}
The problem was that the return value of doSomething() function is returned and assigned to onTouchTap. Instead you should just pass the function name, without paranthesis.
One solution can be this.
class MyOwnComponent extends Component {
doSomething = () => {
alert('doSomething: id = ' + this.props.object.id );
}
render() {
return (
<RaisedButton secondary={true} label={'My label'} onTouchTap=
{this.doSomething}/>
);
}
}
Alternatively you can use also use
<RaisedButton secondary={true} label={'My label'} onTouchTap={()=>
this.doSomeThing(id) /> // eslint-disable-line
I tried your sollution. However when I use onTouchTap={() => this.doSomething(id)} the page wont load because the browser says JSX props should not use arrow functions.
And the id is from the props. At the top of the render method I say
const { id } = this.props.object

Categories

Resources