How to add two event for the On submit - reactjs

How to add react typescript forms in the two events for the onSubmit
<Form onSubmit={this.onSaveMybus}> and onSubmit={handleSubmit}
Anyone know how to add this correctly

<Form onSubmit={() => {this.onSaveMybus();this.handleSubmit()}>
you can call this way two function at a time in react

You can't call onSubmit two times, so call other method from first onSubmit method.
const onSaveMybus = () =>
{
// perform some task here
handleSubmit();
}
const handleSubmit = () =>
{
// perform some other task here
}
<Form onSubmit={onSaveMybus}></Form>

const firstFunction = () => {
...doFirstStuff
}
const secondFunction = () => {
...doSecondStuff
}
const onSaveMybus = () => {
firstFunction()
secondFunction()
}
<Form onSubmit={onSaveMybus} />

Related

(Jest/Enzyme/React) How to assert that throttled function inside change handler has been called?

I need to assert that SearchInputActions.onSearchActivated(value) is called when something is written in an input. It is a callback which is in change handler handleChange. I've been trying to create to mocks - one for handleChange and one for search but it did not work either. I am using jest and enzyme for tests.
const SearchInput = () => {
const search = throttle(event => {
const value = event.target.value;
SearchInputActions.onSearchActivated(value);
});
const handleChange = event => {
event.persist();
search(event);
};
return (
<div>
<SomeChildComponent />
<input type="text" onChange={handleChange} />
</div>
)
}
Test:
it('should dispatch search action', async () => {
const tree = mount(<SearchInput />);
const spySearch = jest.spyOn(SearchInputActions, 'onSearchActivated');
SearchInputActions.onSearchActivated.mockImplementation(() => {})
tree.find('input').simulate('change', {target: value: 'test'}});
expect(spySearch).toBeCalled();
}
I figured it out: Because the callback function was throttled (lodash throttle) I needed to add jest.useFakeTimers(); Final code looks like this:
jest.useFakeTimers();
it('should dispatch search action', async () => {
const tree = mount(<SearchInput />);
const spySearch = jest.spyOn(SearchInputActions, 'onSearchActivated');
SearchInputActions.onSearchActivated.mockImplementation(() => {})
tree.find('input').simulate('change', {target: value: 'test'}});
expect(spySearch).not.toBeCalled();
jest.runAllTimers();
expect(spySearch).toBeCalled();
SearchInputActions.onSearchActivated.mockRestore();
}

How to read the value of updated array while using useState hook in react?

I am trying to build my 1st ToDo-list-app in React & I can't seem to successfully read the data from my "list" array which I've initiated using useState([]).
The issue I'm facing is - if my 1st entered task is "1-Eat Breakfast" & I click on the add button, I'm getting an empty array in console.log,
When I enter my 2nd task lets say - "2-Hit the gym"; that's when my previous task is getting console logged. So, apparently I am unable to read the latest state of my array - "list".
Can you please point out what I am doing wrong in the code given below?
Thanks a lot.
import { useState } from "react";
const ToDo = () => {
const [task, setTask] = useState("");
const [list, setList] = useState([]);
const readData = (event) => {
event.preventDefault();
setTask(event.target.value);
};
const showList = (event) => {
event.preventDefault();
setList([...list, task]);
console.log(list);
};
return (
<div>
<div>
<form onSubmit={showList}>
<input type="text" value={task} onChange={readData} />
<button>Add to List</button>
</form>
</div>
</div>
);
};
export default ToDo;
can you change
const showList = (event) => {
event.preventDefault();
setList([...list, task]);
console.log(list);
};
to
const showList = (event) => {
event.preventDefault();
list.push(task);
setList(list);
console.log(list);
};

Using React hook form getValues() within useEffect return function, returns {}

I'm using react-hook-form library with a multi-step-form
I tried getValues() in useEffect to update a state while changing tab ( without submit ) and it returned {}
useEffect(() => {
return () => {
const values = getValues();
setCount(values.count);
};
}, []);
It worked in next js dev, but returns {} in production
codesandbox Link : https://codesandbox.io/s/quirky-colden-tc5ft?file=/src/App.js
Details:
The form requirement is to switch between tabs and change different parameters
and finally display results in a results tab. user can toggle between any tab and check back result tab anytime.
Implementation Example :
I used context provider and custom hook to wrap setting data state.
const SomeContext = createContext();
const useSome = () => {
return useContext(SomeContext);
};
const SomeProvider = ({ children }) => {
const [count, setCount] = useState(0);
const values = {
setCount,
count
};
return <SomeContext.Provider value={values}>{children}</SomeContext.Provider>;
};
Wrote form component like this ( each tab is a form ) and wrote the logic to update state upon componentWillUnmount.
as i found it working in next dev, i deployed it
const FormComponent = () => {
const { count, setCount } = useSome();
const { register, getValues } = useForm({
defaultValues: { count }
});
useEffect(() => {
return () => {
const values = getValues(); // returns {} in production
setCount(values.count);
};
}, []);
return (
<form>
<input type="number" name={count} ref={register} />
</form>
);
};
const DisplayComponent = () => {
const { count } = useSome();
return <div>{count}</div>;
};
Finally a tab switching component & tab switch logic within ( simplified below )
const App = () => {
const [edit, setEdit] = useState(true);
return (
<SomeProvider>
<div
onClick={() => {
setEdit(!edit);
}}
>
Click to {edit ? "Display" : "Edit"}
</div>
{edit ? <FormComponent /> : <DisplayComponent />}
</SomeProvider>
);
}

React state not correct when function called via addEventListener

I have a React component that uses state to manage a changed variable if a form input is updated.
Assuming I've made some updates to the form, the issue I'm having is if I dispatch a click event to the onCancel function using addEventListener the value of changed is not correct but if I call onCancel from the JSX the value is correct.
Any ideas?
const Edit = (props) => {
let [changed, setChanged] = useState(false);
// Fired when a form value is updated
const onChange = (e) => {
setChanged("true");
};
// Close modal
const onCancel = () => {
console.log(changed); // This will be false when triggered from addEventListener
};
useEffect(() => {
let form = document.querySelector(".oda-edit-form");
// Close Window on click outside
form.addEventListener("click", function () {
onCancel();
});
}, []);
return (
<div>
<input type="text" onChange={(e) => onChange(e)} />
<button onClick={onCancel}>Close</button>
</div>
);
};
You need to re render your component as soon your state changes to run the onCancel() funtion.
let form = document.querySelector(".oda-edit-form");
// Close Window on click outside
form.addEventListener("click", function () {
onCancel();
});
}, [changed]); // < ----- add dependancy
Removed the addEventListener and added an onClick directly to the JSX with a custom method.
const Edit = (props) => {
let [changed, setChanged] = useState(false);
// Fired when a form value is updated
const onChange = (e) => {
setChanged("true");
};
// Close modal
const onCancel = () => {
console.log(changed); // This will be false when triggered from addEventListener
};
const onClickOutside = (e) => {
let element = e.target.querySelector('.wide-card');
let isClickInside = element.contains(event.target);
// // Close Modal
if (!isClickInside) {
onCancel();
}
};
return (
<div onClick-{(e)=>onClickOutside(e)}>
<input type="text" onChange={(e) => onChange(e)} />
<button onClick={onCancel}>Close</button>
</div>
);
};

Hide and Show modal on mouseenter and mouseleave using React Hooks

I tried adding the condition on mouseenter and mouseleave however the modal is not working but when I tried to create a button onClick={() => {openModal();}} the modal will show up. Can you please tell me what's wrong on my code and which part.
const openModal = event => {
if (event) event.preventDefault();
setShowModal(true);
};
const closeModal = event => {
if (event) event.preventDefault();
setShowModal(false);
};
function useHover() {
const ref = useRef();
const [hovered, setHovered] = useState(false);
const enter = () => setHovered(true);
const leave = () => setHovered(false);
useEffect(() => {
if (ref.current.addEventListener('mouseenter', enter)) {
openModal();
} else if (ref.current.addEventListener('mouseleave', leave)) {
closeModal();
}
return () => {
if (ref.current.addEventListener('mouseenter', enter)) {
openModal();
} else if (ref.current.addEventListener('mouseleave', leave)) {
closeModal();
}
};
}, [ref]);
return [ref, hovered];
}
const [ref, hovered] = useHover();
<div className="hover-me" ref={ref}>hover me</div>
{hovered && (
<Modal active={showModal} closeModal={closeModal} className="dropzone-modal">
<div>content here</div>
</Modal>
)}
building on Drew Reese's answer, you can cache the node reference inside the useEffect closure itself, and it simplifies things a bit. You can read more about closures in this stackoverflow thread.
const useHover = () => {
const ref = useRef();
const [hovered, setHovered] = useState(false);
const enter = () => setHovered(true);
const leave = () => setHovered(false);
useEffect(() => {
const el = ref.current; // cache external ref value for cleanup use
if (el) {
el.addEventListener("mouseenter", enter);
el.addEventListener("mouseleave", leave);
return () => {
el.removeEventLisener("mouseenter", enter);
el.removeEventLisener("mouseleave", leave);
};
}
}, []);
return [ref, hovered];
};
I almost gave up and passed on this but it was an interesting problem.
Issues:
The first main issue is with the useEffect hook of your useHover hook, it needs to add/remove both event listeners at the same time, when the ref's current component mounts and unmounts. The key part is the hook needs to cache the current ref within the effect hook in order for the cleanup function to correctly function.
The second issue is you aren't removing the listener in the returned effect hook cleanup function.
The third issue is that EventTarget.addEventListener() returns undefined, which is a falsey value, thus your hook never calls modalOpen or modalClose
The last issue is with the modal open/close state/callbacks being coupled to the useHover hook's implementation. (this is fine, but with this level of coupling you may as well just put the hook logic directly in the parent component, completely defeating the point of factoring it out into a reusable hook!)
Solution
Here's what I was able to get working:
const useHover = () => {
const ref = useRef();
const _ref = useRef();
const [hovered, setHovered] = useState(false);
const enter = () => setHovered(true);
const leave = () => setHovered(false);
useEffect(() => {
if (ref.current) {
_ref.current = ref.current; // cache external ref value for cleanup use
ref.current.addEventListener("mouseenter", enter);
ref.current.addEventListener("mouseleave", leave);
}
return () => {
if (_ref.current) {
_ref.current.removeEventLisener("mouseenter", enter);
_ref.current.removeEventLisener("mouseleave", leave);
}
};
}, []);
return [ref, hovered];
};
Note: using this with a modal appears to have interaction issues as I suspected, but perhaps your modal works better.

Resources