States returned from custom hook undfined - reactjs

State returned from custom hook is undefined. Why is it undefined I do not understand, in the form below I am trying to get states from the custom useInput hook but they are undefined, what is the problem here?
Custom hook
import {useState} from 'react';
export default function useInput (checkValidity){
const [value,setValue] = useState('');
const[isTouched,setIstouched]= useState(false);
let isThisInValid = !checkValidity(value) && isTouched;
var changeValidity = (event)=>{
setValue(event.target.value);
}
var submitTheValue = (event)=>{
event.preventDefault();
setIstouched(true);
}
return {
isThisInValid :isThisInValid,
changeValidity:changeValidity,
submitTheValue:submitTheValue,
}
}
Form in which i am trying to get value from custom hook
import React from 'react'
import Button from '../Button/Button.js'
import {useState,useRef} from 'react'
import Style from '../Input.module.css'
import useInput from '../hooks/useInput'
function BasicInput (props){
const {validityofInput, //trying to get state from custom hook
changeInputValidity,
submitTheValue,
}
= useInput((value) => value.trim()=='');
const {validityofEmail,
changeEmailValidity,
submitTheSecondValue,
}
= useInput((value) => value.includes('#'));
console.log(validityofEmail) //undefined
console.log(validityofInput) //undefined
return <>
<form className = {Style.form}
onSubmit = {submitTheValue}
noValidate
>
<div>Name</div>
<input
id="input"
className = { validityofInput && Style.wrong}
onChange = {
changeInputValidity
}/>
<div>Email</div>
<input
type = "email"
id="input"
className = {validityofEmail && Style.wrong}
onChange = {
changeEmailValidity
}/>
<Button name = "CLICK ME"> </Button>
</form>
</>
}
export default BasicInput;

You are returning an object in the hook with these properties:
return {
isThisInValid :isThisInValid,
changeValidity:changeValidity,
submitTheValue:submitTheValue,
}
and you are destructing from the hook these properties:
const {validityofInput, // notice here it must be "isThisInValid"
changeInputValidity, // and here must be "changeValidity"
submitTheValue,
}
You can rename the properties like this if you want:
const {isThisInValid: validityofInput,
changeValidity:changeInputValidity,
submitTheValue,
}

Related

How to use variable from script A in srcript B typescript?

I want to get variable from other script to build the next part of the page on the basis of this data.
This is code to get data from API:
import Axios from "axios";
import React from "react";
export default class PersonList extends React.Component {
state = {
dataURL: [], //from this variable I want get data
};
componentDidMount() {
Axios.get(
"https://g.tenor.com/v1/search?q=" +
"mems" +
"&key=" +
"MY_TENOR_API_KEY" +
"&limit=" +
"1"
).then((res) => {
this.state.dataURL = res.data;
this.setState({ dataURL });
console.log(this.state.dataURL);
});
}
render() {
return;
}
}
Here I want to dynamically import the script and try to get access to variable from other script
import { useState } from "react";
import styles from "../styles/Form.module.scss";
function Form() {
const [results, setResults] = useState();
return (
<div className={styles.container}>
<div className={styles.form}>
<input
type="button"
onClick={async (e) => {
const { value } = e.currentTarget;
const Fuse = (await import("../pages/api/tenor")).default;
const fuse = new Fuse(state); //I got there an error: "Cannot find name 'state'.ts(2304)"
setResults(fuse.search(value));
}}
/>
</div>
</div>
);
}
export default Form;
Basically, if you want to access a component's data from a different component you have a few options you can choose from.
Send that data as a prop.
(only relevant if the 2nd component is a child/grand-child/etc.. of the 1st component)
Manage a "global state" (a single source containing the app's relevant data).
This can be achieved via 3rd-party libraries (Redux / MobX / etc..)
Or even via React's built-in ContextAPI.
Use a shared hook containing the state which can then be accessed from other components.
(only relevant for functional components)
IMO, the simplest option is the 3rd, but it will require turning PersonList into a functional hook.
An example should look like this:
// Shared "PersonList" hook.
import Axios from "axios";
import React, { useState } from "react";
export function usePersonList() {
const [dataURL, setDataURL] = useState([]);
useEffect(() => {
Axios.get(
"https://g.tenor.com/v1/search?q=" +
"mems" +
"&key=" +
"MY_TENOR_API_KEY" +
"&limit=" +
"1"
).then(res => setDataURL(res.data));
}, []);
return dataURL;
}
// Form.tsx
import { useState } from "react";
import styles from "../styles/Form.module.scss";
function Form() {
const [results, setResults] = useState();
const dataURL = usePersonList();
return (
<div className={styles.container}>
<div className={styles.form}>
<input
type="button"
onClick={async (e) => {
const { value } = e.currentTarget;
const Fuse = (await import("../pages/api/tenor")).default;
const fuse = new Fuse(dataURL);
setResults(fuse.search(value));
}}
/>
</div>
</div>
);
}
export default Form;
You can try React Redux or useReducer to share variable between components.

How do I get a state variable from child to parent?

I am learning React.
I have Component structure like this -
index.js
import React from "react";
import Button from "./Button/Button"
export default function Index() {
return (
<>
<Button />
<div>Value of flag in Index.js = {}</div>
</>
);
}
Button.js
import React, { useState } from "react";
import "./button.css";
export default function Button(props) {
const [flag, setFlag] = useState(true);
const clickHandler = () => {
setFlag(!flag);
};
return (
<div className="btn" onClick={clickHandler}>
Value of flag in Button.js = {flag.toString()}
</div>
);
}
My question is "How do I get flag value from Button.js to index.js" ? (child to parent).
1) You can lift state in parent component and pass state and handler as a prop to children.
Note: This is will work because you need flag in the JSX, But if you will pass event handler as a prop in the child component then you have to invoke the handler to get the value. So Either lift the state or use Redux
Live Demo
App.js
const App = () => {
const [flag, setFlag] = useState( true );
return (
<>
<Button flag={flag} setFlag={setFlag} />
<div>Value of flag in Index.js = { flag.toString() }</div>
</>
);
};
Button.js
export default function Button({ flag, setFlag }) {
const clickHandler = () => {
setFlag(oldFlag => !oldFlag);
};
return (
<div className="btn" onClick={clickHandler}>
Value of flag in Button.js = {flag.toString()}
</div>
);
}
2) You can pass handler as a prop in child component as shown in the Harsh Patel answer
3) You can use state management tool i.e. Redux.
You can send a value by method, refer to this:
index.js
import React from "react";
import Button from "./Button/Button"
export default function Index() {
let getFlagValue = (flag) => {
//here you'll get a flag value
console.log(flag)
}
return (
<>
<Button sendFlagValue=(getFlagValue)/>
<div>Value of flag in Index.js = {}</div>
</>
);
}
Button.js
import React, { useState } from "react";
import "./button.css";
export default function Button(sendFlagValue) {
const [flag, setFlag] = useState(true);
const clickHandler = () => {
setFlag(!flag);
sendFlagValue(flag)
};
return (
<div className="btn" onClick={clickHandler}>
Value of flag in Button.js = {flag.toString()}
</div>
);
}
There are two types state:
global state for all
private state for component
For starter, you must obey some policies, not try abuse state, otherwise you will have some troubles.
For global STATE, you can use Redux or dva or umijs.
For private STATE, you seems already known.

how to set value in hooks

I have a problem with hooks in ReactJS
as you see here i defined a prop that should call from child component
but when i want to change the value by calling change component it doesn't work and my state doesn't set.
can someone help me?
don't forget to read the comments
import React, {useState} from "react";
import Collection from "./Collection";
import ReminderPeriod from "./ReminderPeriod";
function SingleReminderPage() {
const [collection, setCollection] = useState(null);
const setSelectedCollection = (e) => {
setCollection(e);
console.log(e); // returns the true value
console.log(collection); // returns null
}
return(
<div>
<Collection onChoosed={(e) => setSelectedCollection(e)}/>
</div>
)
}
export default SingleReminderPage;
Use setState with a callback function
const setSelectedCollection = (e) => {
setCollection((state)=> {...state, e});
}
setCollection(e) - wont update the state immediately.
I want to Understand SetState and Prevstate in ReactJS
This might help you around, the useEffect will be called on each colletion update
import React, { useState, useEffect } from "react";
import Collection from "./Collection";
import ReminderPeriod from "./ReminderPeriod";
function SingleReminderPage() {
const [collection, setCollection] = useState(null);
useEffect(() => {
console.log(collection)
}, [collection])
return (
<div>
<Collection onChoosed={(e) => setCollection(e)} />
</div>
)
}
export default SingleReminderPage;
it seems like the setCollection is called after the logging action to check something like that you can print the collection value on the component itself
import React, {useState} from "react";
import Collection from "./Collection";
import ReminderPeriod from "./ReminderPeriod";
function SingleReminderPage() {
const [collection, setCollection] = useState(null);
const setSelectedCollection = (e) => {
setCollection(e);
console.log(e); // returns the true value
console.log(collection); // returns null
}
return(
<div>
{collection}
<Collection onChoosed={(e) => setSelectedCollection(e)}/>
</div>
)
}
export default SingleReminderPage;

Unable to set the checked state of the checkbox

I created a custom react component. I am able to fetch the state of the checkbox, when it is changed on a user action. However i am not able to set the checked state when i invoke the component and set the checked state to the prop. Here is my code
import React, { FunctionComponent, SyntheticEvent, useState } from 'react';
import nanoid from 'nanoid';
import classNames from 'classnames';
import { mapToCssModules } from 'utils';
import VolumeComponentProps from 'utils/props';
export interface CheckboxProps extends VolumeComponentProps {
/** Is selected */
checked?: boolean;
/** disabled - Sets or Gets the property if the input is disabled or not */
disabled?: boolean;
/** on Change event, raised when the input is clicked */
onInputChange?: (e: SyntheticEvent, updatedState: boolean) => void;
}
export const Checkbox: FunctionComponent<CheckboxProps> = ({
checked = false,
children,
className,
cssModule,
disabled = false,
onInputChange,
...attributes
}: CheckboxProps) => {
const valueCheck = checked ? true : false;
const [inputId] = useState(`checkbox_${nanoid()}`);
const [isChecked, setIsChecked] = useState(valueCheck);
const containerClasses = mapToCssModules(classNames(className, 'vol-checkbox'), cssModule);
const checkboxInputClass = mapToCssModules(classNames('vol-checkbox__input'), cssModule);
const checkboxClass = mapToCssModules(classNames('vol-checkbox__input-control'), cssModule);
const onChangeHandler = (e: SyntheticEvent) => {
setIsChecked((e.currentTarget as HTMLInputElement).checked);
if (onInputChange) {
onInputChange(e, isChecked);
}
};
return (
<>
{isChecked && <span>true</span>}
<label className={containerClasses} htmlFor={inputId}>
<input
{...attributes}
id={inputId}
className={checkboxInputClass}
disabled={disabled}
checked={isChecked}
type="checkbox"
onChange={onChangeHandler}
/>
<span className={checkboxClass} />
</label>
</>
);
};
export default Checkbox;
So, if i invoke my checkbox as
<Checkbox onChange=()=>{} checked />
The checked value is not set to the checkbox, it works when i click it manually.
Update
This issue is only happening from Storybook. When i create a knob Checked, to alter states, that feature is not working. Here is my story.
import React from 'react';
import { storiesOf } from '#storybook/react';
import { boolean } from '#storybook/addon-knobs';
import { action } from '#storybook/addon-actions';
import Checkbox from './Checkbox';
storiesOf('Pure|Checkbox ', module).add(' Checkbox', () => {
return (
<Checkbox
disabled={boolean('Disabled', false)}
checked={boolean('Checked', false)}
onInputChange={action('onChangeHandler')}
/>
);
});
Your code should work, but you can simplify it by just toggling the isChecked state when the onChange event is fired. onChange means value changed and since a checked input has only two possible variables, we can safely assume that the value toggles, so no need to get the value from the event object each time.
Like this:
const onChangeHandler = () => {
setIsChecked(!isChecked);
if (onInputChange) {
onInputChange(e, !isChecked); // also, this line should pass the updated value
}
};

Why is my search function not being passed?

I am trying to pass a search filter function into my search bar components. But i keep getting this error TypeError: Cannot read property 'search' of undefined
the search function is not recognized my context file is here
https://github.com/CodingOni/Ecommerce-Store/blob/master/src/context.js
import React, { useContext, useEffect, useRef } from 'react';
import ProductContext from '../../src/context';
const ProductFilter = () => {
const productConsumer = useContext(ProductContext);
const text = useRef('');
const { search, searchResults } = productConsumer;
useEffect(() => {
console.log(` product context ${productConsumer}`)
});
const onChange = e => {
if (text.current.value !== '') {
search(e.target.value);
} else {
}
};
return (
<form>
<input
ref={text}
type="text"
placeholder="Search Keywords..."
onChange={onChange}
id=""
/>
</form>
);
};
export default ProductFilter;
useContext accepts a context object (the value returned from
React.createContext) and returns the current context value for that
context.
You pass react component to useContext which is default export from '../../src/context'.
In context file you need export PoductContext
export { ProductProvider, ProductConsumer, ProductContext };
..
import {ProductContext} from '../../src/context';

Resources