How to write test cases for useAsyncDebounce of react table? - reactjs

Below is the snapshot of my search filter code of table component(react-table). I'm trying to cover test cases for unreachable code using jest. Is their anyway to cover test cases for onAsyncDebounceChange method?
import { React, useMemo, useState } from "react";
import { useAsyncDebounce } from "react-table";
import { Label, Input } from "reactstrap";
import { isValidSearchInput } from "./helper"
// Component for Global Filter
export function GlobalFilter({ globalFilter, setGlobalFilter }) {
const [value, setValue] = useState(globalFilter);
const onChange = value => {
if (isValidSearchInput(value)) {
setValue(value);
onAsyncDebounceChange(value);
}
};
const onAsyncDebounceChange = useAsyncDebounce(value => {
setGlobalFilter (value);
}, 500);
return (
<div>
<Label>Search Table: </Label>
<Input
value={value || ""}
onChange={(e) => {
onChange(e.target.value);
}}
placeholder=" Enter value "
/>
</div>
);
}

Related

using Redux form, working with react-select,integrating with redux-form, but handle submit is not working

i am working on Select feature, where i need to select a value from the select field. i am using redux-form, and working with react-select and integrating with redux-form. when i select a option from the list of option, handleSubmit function is not being triggred. below is the code snippet of react-form -Field implementation
import React from "react";
import { Field, reduxForm } from "redux-form";
import ReduxFormSelect from "./ReduxFormSelect";
const SelectInputField = (props) => {
const { userOptions, handleSubmit, name } = props;
return (
<form onSubmit={handleSubmit}>
<Field
name={name}
component={ReduxFormSelect}
sytle={styles.selectInput}
options={userOptions}
/>
</form>
);
};
export default reduxForm({
form: "wizard",
initialValues: {
FilterFor: {
label: "correct",
value: "correct",
},
},
})(SelectInputField);
below is the code where i am using Select component from react-select integrating the input field
generated by redux-form -- ReduxFormSelect component
import React from "react";
import Select from "react-select";
const ReduxFormSelect = (props) => {
const { input, options } = props;
return (
<Select
{...input}
onChange={(value) => {
input.onChange(value);
}}
onBlur={() => input.onBlur(input.value)}
options={options}
/>
);
};
export default ReduxFormSelect;
below is where the handleSubmit function is sent as props to SelectInputComponent, where this handleSubmit function is not being triggered, when one of the options being changed
import React, { Fragment } from "react";
import { Container, Row, Col } from "react-bootstrap";
import { connect } from "react-redux";
import { reduxForm } from "redux-form";
import { filteredResultsAction } from "../../Actions";
import SelectInputField from "../reusableComponents/SelectInputField";
import ShowFilteredResults from "./ShowFilteredResults";
const ShowAttemptedQue = (props) => {
const { ans, opt_values } = props;
const handleSubmit = (values) => {
console.log("changed option values",values);
};
return (
<Fragment>
<Container>
<Row>
<Col>Attempted Questions:</Col>
<Col md="auto">
Filted By :{" "}
<SelectInputField
name="filterFor"
userOptions={opt_values}
handleSubmit={handleSubmit}
/>
</Col>
</Row>
<ShowFilteredResults result_data={ans} />
</Container>
</Fragment>
);
};
const mapStateToProps = (state) => {
return {
ans: state.updatedTempVal.attempted,
opt_values: state.updatedTempVal.options,
};
};
export default connect(mapStateToProps, { filteredResultsAction })(
ShowAttemptedQue
);
where am i going wrong?

Passing multiple form input fields' data in a child component to its parent in React (hooks)

I have a child component that isn't re-rendering because the state inside its parent isn't updating. I've recently found out that I need to pass data from child to parent, but I'm not sure how to do that. Most tutorials I've found on the subject show you how to pass one field or piece of information over to the parent by sending a function, but I have multiple fields on a form I need to send over to the parent component. I'm not sure how to go about that.
Here's the parent component.
import React, { useState } from "react";
import { useQuery } from "#apollo/client";
import { getStudents } from "../queries";
import StudentDetails from "./StudentDetails";
const StudentList = () => {
const [student, setStudent] = useState("");
const { loading, error, data } = useQuery(getStudents);
if (loading) return <p>Loading...</p>;
if (error) return <p>Error!</p>;
const handleClick = (student)=> {
//console.log(student)
setStudent(student);
};
let filteredStudents = [];
//console.log(data.students)
for(let i = 0; i < data.students.length; i++){
//console.log(data.students[i].class.name)
if(data.students[i].class.name === "1FE1"){
//console.log(data.students[i].name)
filteredStudents.push(data.students[i])
}
}
//console.log(filteredStudents);
return (
<div>
<ul id="student-list">
{data.students.map((student) => (
<li key={student.id} onClick={(e) => handleClick(student)}>{student.name}</li>
))}
</ul>
{
student ? <StudentDetails student={student} />
: <p>No Student Selected</p>
}
</div>
);
};
export default StudentList;
And here is the child component called StudentDetails which displays a student's individual information that isn't re-rendering because StudentList's state isn't changing.
import React from "react";
import { useEffect, useState } from "react";
import { getStudentQuery } from "../queries";
import { useQuery } from "#apollo/client";
import DeleteStudent from "./DeleteStudent"
import EditStudent from "./EditStudent";
const StudentDetails = (props)=> {
console.log(props)
const [astudent, setStudent] = useState(props)
return (
<div id="student-details" >
<h2>Name: {props.student.name}</h2>
<h3>Age: {props.student.age}</h3>
<h3>Class: {props.student.class.name}</h3>
<h3>Test 1 Score: {props.student.test1}</h3>
<DeleteStudent id={props.student.id}/>
<EditStudent id={props.student.id} />
</div>
)
}
export default StudentDetails;
Inside StudentDetails is another child component called "EditStudent" which is where I need to somehow pass the information submitted in the form's fields over to StudentList.
import React, { useEffect, useState } from "react";
import { useMutation } from "#apollo/react-hooks";
//import { getStudents } from "../queries";
import StudentDetails from "./StudentDetails";
import { editStudentMutation, getStudentQuery, getStudents } from "../queries/index";
const EditStudent = (props) => {
console.log(props)
const [name, setName] = useState();
const [age, setAge] = useState();
const [test, setTest] = useState();
const [editStudent] = useMutation(editStudentMutation);
const astudent = props
return (
<form id="edit-student"
onSubmit={(e) => {
e.preventDefault();
editStudent({
variables: {
id: props.id,
name: name,
age: age,
test1: test
},
refetchQueries: [{ query: getStudents}]
});
}}>
<div className="field">
<label>Student Name:</label>
<input type="text"
value={name}
onChange={(e) => setName(e.target.value)}/>
</div>
<div className="field">
<label>Age:</label>
<input type="text"
value={age}
onChange={(e) => setAge(e.target.value)}/>
</div>
<div className="field">
<label>Test One:</label>
<input type="text"
value={test}
onChange={(e) => setTest(e.target.value)}/>
</div>
<button>submit</button>
</form>
)
}
export default EditStudent;
So yeah, I think I understand what I need to do but I don't know where to start on how to pass all the info from EditStudent over to StudentList. As I mentioned, all the tutorials on the subject show how to send one individual piece of information, but not several pieces. Could anyone suggest any pointers on how to achieve this?
I think what you are looking for is lifting a state up; essentially the parent passes a state to the child component and they both can access and change the state. For your case I would suggest passing multiple states down to the child.
Here is an example that does this: enter link description here

React Lifting State: Updating state in the child using setState function from parent

I've been working on variations of this problem for a while now. Basically, I have a child component that can update existing data. It updates data with no problems and the parent re-renders accordingly. The child component doesn't re-render though. So, on advice given on this site, I've tried lifting the state. I'm passing down props down to the two child components I'm running. My problem is the "EditStudent" component. I can't seem to destructure/get the "setStudent" function that's being passed down from the parent component so I'm getting a "setStudent is not a function error" no matter how I try to call this function. Any advice is greatly appreciated as it's been driving me slowly insane on how to figure this out.
Here's the code I've been working with so far.
Parent component "StudentList"
import React, { useState } from "react";
import { useQuery } from "#apollo/client";
import { getStudents } from "../queries";
import StudentDetails from "./StudentDetails";
import DeleteStudent from "./DeleteStudent";
import EditStudent from "./EditStudent";
const StudentList = () => {
const [selectedStudent, setSelectedStudent] = useState("");
const { loading, error, data } = useQuery(getStudents);
if (loading) return <p>Loading...</p>;
if (error) return <p>Error!</p>;
const handleClick = (student)=> {
//console.log(student)
setSelectedStudent(student);
};
let filteredStudents = [];
//console.log(data.students)
for(let i = 0; i < data.students.length; i++){
//console.log(data.students[i].class.name)
if(data.students[i].class.name === "1FE1"){
//console.log(data.students[i].name)
filteredStudents.push(data.students[i])
}
}
console.log(selectedStudent.id);
return (
<div>
<ul id="student-list">
{data.students.map((student) => (
<li key={student.id} onClick={(e) => handleClick(student)}>{student.name}</li>
))}
</ul>
{
selectedStudent ? <div>
<StudentDetails student={selectedStudent} setStudent={setSelectedStudent}/>
</div>
: <p>No Student Selected</p>
}
</div>
);
};
export default StudentList;
This is "StudentDetails" - a component receiving the "studentDetails" prop and also has two other components nested inside - "DeleteStudent" and "EditStudent"
import React from "react";
import { useEffect, useState } from "react";
import { getStudentQuery } from "../queries";
import { useQuery } from "#apollo/client";
import DeleteStudent from "./DeleteStudent"
import EditStudent from "./EditStudent";
const StudentDetails = ( selectedStudent )=> {
const {setStudent} = selectedStudent;
console.log(selectedStudent)
//const [astudent, setStudent] = useState(props)
return (
<div id="student-details" >
<h2>Name: {selectedStudent.student.name}</h2>
<h3>Age: {selectedStudent.student.age}</h3>
<h3>Class: {selectedStudent.student.class.name}</h3>
<h3>Test 1 Score: {selectedStudent.student.test1}</h3>
<EditStudent student={selectedStudent} setstudent={setStudent}/>
<DeleteStudent student={selectedStudent} setter={setStudent} />
</div>
)
}
export default StudentDetails;
Finally, here is the "EditStudent" component which is causing me so many problems (can't get the setStudent function from the parent to change the state)
import React, { useEffect, useState } from "react";
import { useMutation } from "#apollo/react-hooks";
//import { getStudents } from "../queries";
import StudentDetails from "./StudentDetails";
import { editStudentMutation, getStudentQuery, getStudents } from "../queries/index";
const EditStudent = ( setStudent ) => {
const { setStudent } = selectedStudent;
console.log(props)
const [name, setName] = useState();
const [age, setAge] = useState();
const [test, setTest] = useState();
const [editStudent] = useMutation(editStudentMutation);
return (
<form id="edit-student"
onSubmit={(e) => {
e.preventDefault();
editStudent({
variables: {
id: selectedStudent.student.student.id,
name: name,
age: age,
test1: test
},
refetchQueries: [{ query: getStudents}]
})
const aStudent = e.target.value;
setStudent(aStudent);
}}>
<div className="field" onChange={(e) => setName(e.target.value)}>
<label>Student Name:</label>
<input type="text"
value={name}/>
</div>
<div className="field" onChange={(e) => setAge(e.target.value)}>
<label>Age:</label>
<input type="text"
value={age}/>
</div>
<div className="field" onChange={(e) => setTest(e.target.value)}>
<label>Test One:</label>
<input type="text"
value={test}/>
</div>
<button type="submit" >submit</button>
</form>
)
}
export default EditStudent;
Your method named in your props setstudent "check left side of passed props"
<EditStudent student={selectedStudent} setstudent={setStudent}/>
and please access it like the following
const EditStudent = ( {setstudent} ) => {}
// or
const EditStudent = ( props ) => {
props.setstudent()
}
And these lines of code don't seem correct, from where you get this selectedStudent? your props named setStudent then you are accessing it to get the method setStudent
const EditStudent = ( setStudent ) => {
const { setStudent } = selectedStudent;

when i empty my input, this reset the items state of my container. What to do to fix this

I would like my app to make a comparison between two items selected in my container,
when I search a second items Global state 'comparaison' and
local state gonna reinitialized. How to fix it
context component:
import React, { createContext, useState } from 'react'
export const UpperState = createContext()
const GlobalState = (props) =>{
const [pokemons,setPokemons] = useState([])
const [comparaison,setComparaison] = useState({0: null,1: null})
const val = {
pokemons,
comparaison,
setPokemons,
setComparaison
}
return(
<UpperState.Provider value={val}>
{console.log('render')}
{props.children}
</UpperState.Provider>
)
}
export default GlobalState
searchBar component:
import React, { useState } from 'react'
import PokeContainer from './PokeContainer'
export default function SearchBar() {
const [filterText,setFilterText] = useState('')
function handleChange(e) {
setFilterText(e.target.value)
}
return (
<div className='SearchBar'>
<input type="text" name="" id="SearchInput" placeholder='Pokemons...' onChange={handleChange} value={filterText} />
<PokeContainer filterText={filterText} />
</div>
)
}
items container component:
import React, { useState } from 'react'
import PokeContainer from './PokeContainer'
export default function SearchBar() {
const [filterText,setFilterText] = useState('')
function handleChange(e) {
setFilterText(e.target.value)
}
return (
<div className='SearchBar'>
<input type="text" name="" id="SearchInput" placeholder='Pokemons...' onChange={handleChange} value={filterText} />
<PokeContainer filterText={filterText} />
</div>
)
}
items Components:
import React, { useContext, useEffect, useState } from 'react'
import { UpperState } from '../../../contextApi/GlobalState'
export default function PokeRow({data,counter}) {
const val = useContext(UpperState)
const [show, setShow] = useState(false)
useEffect(()=>{
if(show){
if(val.comparaison[0] === null){
val.setComparaison(s=>({
...s,
0:data.id
}))
} else {
val.setComparaison(s=>({
...s,
1:data.id
}))
}
} else {
for(const [key,value] of Object.entries(val.comparaison)){
if(value !== null && value.id === data.id){
val.setComparaison(s=>({
...s,
[`${key}`]:null
}))
}
}
}
},[show])
function handleClick(e){
const targetId = e.target.id
setShow(!show)
if(counter>= 2 && !show){
console.log('2 composant max');
return
}
}
return (
<li id={data.id} onClick={ handleClick } >
{data.langName}: {JSON.stringify(show)}
</li>
)
}
CodeSandBox: https://codesandbox.io/s/funny-agnesi-05wdt?file=/.gitignore

reset React select when options change

How to reset a react-select when the options is changed, this happen because im using chaining select, so my second select options will change based on my first select, what im trying to do is reset back the select to "please select" when my second option already picked before, im using react-select with react-hook-form
import React, { useState, useEffect } from 'react';
import { default as ReactSelect } from 'react-select';
import { FormGroup, Label } from 'reactstrap';
import { useFormContext, Controller } from 'react-hook-form';
import { ErrorMessage } from '#hookform/error-message';
export default function Select(props) {
const {
label,
isMulti,
note,
// isDisabled,
// withDefaultValue,
options,
isClearable,
name,
placeholder = 'Pilihan'
} = props;
const rhfContext = useFormContext(); // retrieve all hook methods
const { control, errors } = rhfContext || {};
const [elOptions, setElOptions] = useState([]);
useEffect(() => {
setElOptions(options);
}, [options]);
return (
<FormGroup>
{label && <Label htmlFor={name || ''}>{label}</Label>}
<Controller
as={ReactSelect}
name={name}
control={control}
options={elOptions}
placeholder={placeholder}
styles={customStyles}
{...(isMulti ? { isMulti: true } : {})}
{...(isClearable ? { isClearable: true } : {})}
classNamePrefix="react-select-pw"
className="react-select-container"
/>
{note && <span>{note}</span>}
<ErrorMessage
name={name}
errors={errors}
render={() => {
return <p className="err-msg">pilih salah satu</p>;
}}
/>
</FormGroup>
);
}
Basically you need to handle the onChange of your react-select
const funcComponent = () => {
const [firstOptions, setFirstOptions] = useState({});
const [secondOptions, setSecondOptions] = useState({});
useEffect(() => {
//Here dispatch your defined actions to load first select options
setFirstOptions(response-data)
})
const handleFirstOptions = selectedVal => {
//Here dispatch your defined action to load second select options
setSecondOptions(response-data)
}
const handleSecondOptions = selectedVal => {
//Your action to perform
}
return (
<Label>First Option Field</Label>
<Select
options={firstOptions}
onChange={handleFirstOptions}
/>
Label>Second Option Field</Label>
<Select
options={secondOptions}
onChange={handleSecondOptions}
/>
)}

Resources