I have rather simple problem.
I don't know why my useState function won't change state -> props
onChangeText={(text) => {
setProps({ ...props, inputValue: text });
}}
I declared my state as here:
const [props, setProps] = useState({
pageNumber: 2,
inputValue: "",
});
Thanks in advance!
prevState received by the updater function is guaranteed to be up-to-date. It's a reference to the component state at the time the change is being applied. Official docs
onChange={(event) => {
setProps(prevState => {
return { ...prevState, inputValue: event.target.value }
});
}}
Also if you have input just use native event onChange instead of custom onChangeText
You wrote 'onChangeText' instead of 'onChange'. And, it gives you the event object rather than the text itself. It should be like this:
<input onChange={(event) => {
setProps({ ...props, inputValue: event.target.value });
}} />
What you doing is correct and nothing is wrong with it.
you need to pass your state value to the input
import { useState } from "react";
export default function App() {
const initialState = {
pageNumber: 2,
inputValue: ""
};
const [props, setProps] = useState(initialState);
const textInputChangeHandler = (e) => {
setProps({ ...props, inputValue: e.target.value });
};
return (
<div className="App">
<input
value={props.inputValue}
type="text"
onChange={textInputChangeHandler}
/>
</div>
);
}
Related
I'm trying to get the value of an autocomplete field outside of my formik component everytime it changes, and i did something like this:
const formRef=useRef<any>(null);
useEffect(() => {
console.log("eee!!",formRef.current?.values?.flagTR)
},[formRef.current?.values]);
return (
<Formik
initialValues={initialValues}
onSubmit={handleSumbit}
enableReinitialize={true}
validateOnChange={true}
validationSchema={ProduitSchema}
innerRef={formRef}
>
the useEffect is triggered the first time the component renders,but then when i change the value of the autocomplete the useEffect doesn't get triggered.
what should i do in order to trgger useEffect everytime a value from formik changes?
Hey so I don't think the approach you are going with here is going to work, it's really not what the useRef hook is for.
The correct approach for what it looks like you want to do is to properly use Formik's context to mapValuesToProps or get access to the values, errors, and validation states.
You can use withFormik() to set up your initial form values and mapValuesToProps. Then you can use within the form component formik's useFormikContext() which will give you access to values, errors, setValues, etc
export default withFormik({
handleSubmit: () => {},
validateOnChange: true,
validateOnBlur: true,
validateOnMount: true,
mapPropsToValues: () => ({ name: '', email: '' }),
initialValues: { name: '', email: '' }
})(MyFormComponent)
In the MyFormComponent you can then call useFormikContext() and do whatever you want when the values change.
const { setValues, values, isValid, validateForm } = useFormikContext()
If for some reason this is not what you want to do, or it does not solve your problem, the only way to achieve what you want in React alone is to useState and and setState each time onChange eg
const MyFormComponent = () => {
const [nameField, nameMeta] = useField(name)
const [emailField, emailMeta] = useField(email)
const [formState, setFormState] = useState({name: '', email: ''})
return (
<Formik
enableReinitialize
validateOnBlur={false}
initialValues={formState}
onSubmit={() => {}}
>
{props => {
const onChange = e => {
const targetEl = e.target
const fieldName = targetEl.name
setFormState({
...formState,
[fieldName]: targetEl.value
})
return props.handleChange(e)
}
return (
<>
<input {...nameField} onChange={onChange}>
<input {...emailField} onChange={onChange}>
</>
)
</Formik>
)
I'm trying to convert an existing react class to a functional component. I understand that functions use the useState() function rather than setState() like in a class. How would I convert this piece of code that handles the change of any input into a functional piece?
handleChange = (input) => (e) => {
this.setState({ [input]: e.target.value });
};
You can have a different useState hook for each field, but you don't have to. You can keep your setup almost the same as in your class component by using a single state object to hold all fields. The primary difference is that with useState you have to provide the entire state, so you need to use ...state to include the unchanged properties.
const Form = () => {
const [state, setState] = React.useState({
first: "",
last: "",
address: ""
});
const handleChange = (input: keyof typeof state) =>
(e: React.ChangeEvent<HTMLInputElement>) => {
setState({
...state,
[input]: e.target.value
});
};
return (
<form>
<input value={state.first} onChange={handleChange("first")} />
<input value={state.last} onChange={handleChange("last")} />
<input value={state.address} onChange={handleChange("address")} />
</form>
);
};
I have a question, if I can use useState generic in React Hooks, just like I can do this in React Components while managing multiple states?
state = {
input1: "",
input2: "",
input3: ""
// .. more states
};
handleChange = (event) => {
const { name, value } = event.target;
this.setState({
[name]: value,
});
};
Yes, with hooks you can manage complex state (without 3rd party library) in three ways, where the main reasoning is managing state ids and their corresponding elements.
Manage a single object with multiple states (notice that an array is an object).
Use useReducer if (1) is too complex.
Use multiple useState for every key-value pair (consider the readability and maintenance of it).
Check out this:
// Ids-values pairs.
const complexStateInitial = {
input1: "",
input2: "",
input3: ""
// .. more states
};
function reducer(state, action) {
return { ...state, [action.type]: action.value };
}
export default function App() {
const [fromUseState, setState] = useState(complexStateInitial);
// handle generic state from useState
const onChangeUseState = (e) => {
const { name, value } = e.target;
setState((prevState) => ({ ...prevState, [name]: value }));
};
const [fromReducer, dispatch] = useReducer(reducer, complexStateInitial);
// handle generic state from useReducer
const onChangeUseReducer = (e) => {
const { name, value } = e.target;
dispatch({ type: name, value });
};
return (
<>
<h3>useState</h3>
<div>
{Object.entries(fromUseState).map(([key, value]) => (
<input
key={key}
name={key}
value={value}
onChange={onChangeUseState}
/>
))}
<pre>{JSON.stringify(fromUseState, null, 2)}</pre>
</div>
<h3>useReducer</h3>
<div>
{Object.entries(fromReducer).map(([key, value]) => (
<input
name={key}
key={key}
value={value}
onChange={onChangeUseReducer}
/>
))}
<pre>{JSON.stringify(fromReducer, null, 2)}</pre>
</div>
</>
);
}
Notes
Unlike the setState method found in class components, useState does not automatically merge update objects. You can replicate this behavior by combining the function updater form with object spread syntax:
setState(prevState => {
// Object.assign would also work
return {...prevState, ...updatedValues};
});
Refer to React Docs.
The correct way to do what you're trying to do is to create your own hook that uses useState internally.
Here is an example:
// This is your generic reusable hook.
const useHandleChange = (initial) => {
const [value, setValue] = React.useState(initial);
const handleChange = React.useCallback(
(event) => setValue(event.target.value), // This is the meaty part.
[]
);
return [value, handleChange];
}
const App = () => {
// Here we use the hook 3 times to show it's reusable.
const [value1, handle1] = useHandleChange('one');
const [value2, handle2] = useHandleChange('two');
const [value3, handle3] = useHandleChange('three');
return <div>
<div>
<input onChange={handle1} value={value1} />
<input onChange={handle2} value={value2} />
<input onChange={handle3} value={value3} />
</div>
<h2>States:</h2>
<ul>
<li>{value1}</li>
<li>{value2}</li>
<li>{value3}</li>
</ul>
</div>
}
ReactDOM.render(<App />, document.querySelector("#app"))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.6/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.6/umd/react-dom.production.min.js"></script>
<div id="app"></div>
Note the use of React.useCallback to stop your hook from returning a new handler function on every render. (We don't need to specify setValue as a dependency because React guarantees that it will never change)
I didn't actually test this, but it should work.
See https://reactjs.org/docs/hooks-reference.html#usestate for more info.
import React, {useState} from 'react';
const MyComponent = () => {
const [name, setName] = useState('Default value for name');
return (<div><button onClick={()=>setName('John Doe')}}>Set Name</button></div>);
};
export default MyComponent;
import React, { useState } from "react";
import Child from "./Child";
import "./styles.css";
export default function App() {
let [state, setState] = useState({
value: ""
});
let handleChange = input => {
setState(prevValue => {
return { value: input };
});
console.log(state.value);
};
return (
<div className="App">
<h1>{state.value}</h1>
<Child handleChange={handleChange} value={state.value} />
</div>
);
}
import React from "react";
function Child(props) {
return (
<input
type="text"
placeholder="type..."
onChange={e => {
let newValue = e.target.value;
props.handleChange(newValue);
}}
value={props.value}
/>
);
}
export default Child;
Here I am passing the data from the input field to the parent component. However, while displaying it on the page with the h1 tag, I am able to see the latest state. But while using console.log() the output is the previous state. How do I solve this in the functional React component?
React state updates are asynchronous, i.e. queued up for the next render, so the log is displaying the state value from the current render cycle. You can use an effect to log the value when it updates. This way you log the same state.value as is being rendered, in the same render cycle.
export default function App() {
const [state, setState] = useState({
value: ""
});
useEffect(() => {
console.log(state.value);
}, [state.value]);
let handleChange = input => {
setState(prevValue => {
return { value: input };
});
};
return (
<div className="App">
<h1>{state.value}</h1>
<Child handleChange={handleChange} value={state.value} />
</div>
);
}
Two solution for you:
- use input value in the handleChange function
let handleChange = input => {
setState(prevValue => {
return { value: input };
});
console.log(state.value);
};
use a useEffect on the state
useEffect(()=>{
console.log(state.value)
},[state])
Maybe it is helpful for others I found this way...
I want all updated projects in my state as soon as I added them
so that I use use effect hook like this.
useEffect(() => {
[temp_variable] = projects //projects get from useSelector
let newFormValues = {...data}; //data from useState
newFormValues.Projects = pro; //update my data object
setData(newFormValues); //set data using useState
},[projects])
I'm trying to change a state hook and I got this error... I know another way to change but it should work with the spread syntax, right?
export default function App() {
const [state, setState] = {
sld_url: "",
geojson_url: "",
}
const handleSldUrlChange = event => {
setState({...state, sld_url: event.target.value})
}
return (
<TextField
label="SLD URL"
value={state.sld_url}
className={classes.textField}
onChange={handleSldUrlChange}
margin="normal"
variant="outlined"
/>
);
}
First thing is you need to useState :
const [state, setState] = useState({
sld_url: "",
geojson_url: "",
})
Than inside handleSldUrlChange function you can use a custom callback for updating state
const handleSldUrlChange = event => {
setState(prev => {...prev, sld_url: event.target.value})
//or
//setState({...state,sld_url: event.target.value})
}
Demo : https://stackblitz.com/edit/react-mv8lsz