Which life cycle method is preferred when using redux and react hooks? - reactjs

In the edit page, by redux useSelector method data available to the component but it is not setting initial values. How to set it?
How to set the initial formData from the store?
In hook component rendering happens 4 times why?
import React,{useState} from 'react'
import { useSelector } from 'react-redux'
import {updateUserInfo} from '../actions/User'
const EditUser = (props) => {
const user = useSelector(state => state.user)
const [formData, setFormData] = useState({email: user.email ,fullName: user.fullName})
console.log(user)
const handleSubmit = e =>{
e.preventDefault();
const id = props.match.params.id
const data = new FormData()
data.append('email', formData.email)
data.append('fullName', formData.fullName)
data.append('image', formData.image)
props.dispatch(updateUserInfo(id,data,props.history))
// console.log(formData)
}
const handleChange = e =>{
setFormData({...formData, [e.target.name]: e.target.value })
}
const fileHandle = (e) =>{
// console.log(e.target.files)
setFormData({...formData,image: e.target.files[0]})
}
return (
<React.Fragment>
<h2>Edit Account</h2>
{Object.keys(user).length > 0 &&
<>
<form onSubmit={handleSubmit}>
<label htmlFor="fullName">Full Name</label>
<input type="text" name="fullName" value={formData.fullName} onChange={handleChange}/>
<br />
<label htmlFor="email">Email</label>
<input type="email" name="email" value={formData.email} onChange={handleChange}/>
<br />
<label htmlFor="image">Upload Image</label>
<input type="file" name="image" onChange={fileHandle}/>
<br />
<button >Update</button>
</form>
</>
}
</React.Fragment>
)
}
export default EditUser

useEffect(() => {
setFormData({email:props.user.email || "", fullName: props.user.fullName || ""}) // update the state if data else it is empty string, if not mentioned empty string you will warning uncontrolled component to controlled component vice-versa
},[props.user])
useEffect Hook as componentDidMount, componentDidUpdate, and componentWillUnmount combined.
When store value available to the component, props.user has properties and values then componentDidUpdate method works.
unnecessary rendering also prevented with useEffect method.

Related

Onchange in input field is not working while editing a form

I am developing a small application in react, in which I have an edit option. On clicking the edit button, it will load the existing data and allows the user to edit any of the fields and submit.
Fetching the data and loading it in a form are working fine, but when I edit a textbox, the value changes to the existing fetched value, and it is not allowing me to hold the edited value.
Please note, the problem is with editing the input in a form not in submitting. Below is the edit component that I am using.
mport { useState, useEffect } from 'react';
import { json, Link } from 'react-router-dom';
import { useParams } from 'react-router-dom';
const EditTask = ({ onEdit }) => {
const [text, setText] = useState('');
const [day, setDay] = useState('');
const [reminder, setReminder] = useState(false);
const params = useParams();
useEffect(() => {
fetchTask();
});
const fetchTask = async () => {
const res = await fetch(`http://localhost:5000/tasks/${params.id}`);
const data = await res.json();
setText(data.text);
setDay(data.day);
setReminder(data.reminder);
};
const onSubmit = async (e) => {
e.preventdefault();
if (!text) {
alert('Please enter task name');
return;
}
onEdit({ text, day, reminder });
setText('');
setDay('');
setReminder(false);
};
const handleChange = ({ target }) => {
console.log(target.value); // displaying the input value
setText(target.value); // changes to existing value not the one I entered
};
return (
<form className="add-form" onSubmit={onSubmit}>
<div className="form-control">
<label>Task</label>
<input
id="AddTask"
type="text"
placeholder="Add Task"
value={text}
onChange={handleChange}
/>
</div>
<div className="form-control">
<label>Date & Time</label>
<input
id="Date"
type="text"
placeholder="Date & Time"
value={day}
onChange={(e) => setDay(e.target.value)}
/>
</div>
<div className="form-control form-control-check">
<label>Set Reminder</label>
<input
id="Reminder"
type="checkbox"
checked={reminder}
value={reminder}
onChange={(e) => setReminder(e.currentTarget.checked)}
/>
</div>
<input className="btn btn-block" type="submit" value="Save Task" />
<Link to="/">Home</Link>
</form>
);
};
export default EditTask;
Can someone explain what I am missing here? Happy to share other information if needed.
Expecting the input fields to get the value entered and submitting.
You missed adding dependency to useEffect
Yours
useEffect(() => {
fetchTask()
}
)
Should be changed
useEffect(()=>{
fetchTask()
}, [])
becasue of this, fetchTask is occured when view is re-rendered.

custom hook to simplify react controlled form

i'd like to simplify form creation avoiding to write for each fied value={} and onChange={} using a custom hook.
this is my code:
https://codesandbox.io/s/busy-noether-pql8x?file=/src/App.js
the problem is that, each time i press the button, the state is cleaned except for the field i've currently edited
import React, { useState } from "react";
import "./styles.css";
const useFormField = (initialValue) => {
const [values, setValues] = React.useState(initialValue);
const onChange = React.useCallback((e) => {
const name = e.target.name;
const value = e.target.value;
setValues( (prevValues) => ({...prevValues,[name]:value}));
}, []);
return { values, onChange };
};
export default function App() {
//hoot to simplify the code,
const {values,onChange} = useFormField({
Salary: "",
Email: ""
})
const onCreateUser = () => {
console.log(values);
};
return (
<div className="App">
<form>
<label htmlFor="Email">Email: </label>
<input name="Email" onChange={onChange} />
<label htmlFor="Email">Salary: </label>
<input name="Salary" onChange={onChange} />
<button type="button" onClick={onCreateUser}>
Send
</button>
</form>
</div>
);
}

Saving object in React.useState

I have a form in my react project, and I want the value of each field to be stored in the state.
instead of having multiple states for each field, how can I store the form value as an object in the state? and more importantly how can I access it? (with react hooks)
import React from 'react';
export const UserData = () => {
return(
<form>
<input type="text" placeholder="Name" />
<input type="email" placeholder="Email" />
<button>Confirm</button>
</form>
)
}
React Hooks allows you to define a JavaScript Object using useState. See
https://daveceddia.com/usestate-hook-examples/
function LoginForm() {
const [form, setState] = useState({
username: '',
password: ''
});
Update the form using the function :
const updateField = e => {
setState({
...form,
[e.target.name]: e.target.value
});
};
Call the function onSubmit of the button
<form onSubmit={updateField}>
<input type="text" placeholder="Name" />
<input type="email" placeholder="Email" />
<Button >Confirm</button>
</form>
You can use useState hook. Check this
const [state, setState] = useState({ name, email });
To set the state similar to setState in class based component:
setState({name: 'react', email: 'react'})
To access the state value:
import React, { useState } from 'react';
export const UserData = () => {
const [state, setState] = useState({ name, email });
return(
<form>
<input type="text" placeholder="Name" value={state.name} />
<input type="email" placeholder="Email" value={state.email} />
<button>Confirm</button>
</form>
)
}
You should create an initial state value if you want to store the form values as an object using useState, so you can rollback to the initial state after an error. Example,
const initialState = {
name: "",
email: ""
};
export const UserData = () => {
const [formState, setFormState] = useState(initialState);
const submitHandler = event => {
event.preventDefault();
console.log(formState);
};
return (
<form onSubmit={submitHandler}>
<input
type="text"
placeholder="Name"
value={formState.name}
onChange={e => {
setFormState({ ...formState, name: e.target.value });
}}
/>
<input
type="email"
placeholder="Email"
value={formState.email}
onChange={e => {
setFormState({ ...formState, email: e.target.value });
}}
/>
<button>Confirm</button>
</form>
);
};
Working demo in codesandbox.

React TypeScript: Alternatives to UseRef in functional components

Is there another way of getting/setting the values from the dom that is less expensive than useRef()? Is useRef() to be used lightly as the docs suggest?
import React, { useRef, useEffect } from 'react';
const Join: React.FC = () => {
const fullName = useRef<HTMLInputElement>(null);
const email = useRef<HTMLInputElement>(null);
const password = useRef<HTMLInputElement>(null);
const myForm = useRef<HTMLFormElement>(null);
useEffect(() => {
if (myForm.current) myForm.current.reset();
if (fullName.current) fullName.current.focus();
}, []);
return (
<div>
<form ref={myForm}>
<input type='text' ref={fullName} />
<input type='text' ref={email} />
<input type='text' ref={password} />
</form>
</div>
)
}
When the component loads I want to clear the form and focus the
fullName input
You don't need refs for that
I want to clear the form
Make your inputs controlled
Declare an empty string as initial value
const Component = () =>{
const [state, setState] = useState({
email : '',
password : ''
})
const onChange = ({ target: { value, name } }) =>{
setState(prev => ({
...prev,
[name] : value
}))
}
const { email, password } = state
return(
<>
<input value={email} onChange={onChange} id='email'/>
<input value={password} onChange={onChange} id='password' />
</>
)
}
Automatically focus a given input
Just use autofocus for that
<input autofocus/>

reactjs container component form values

I am new to react and am trying to get the value from the firstName input in handleSubmit. handleSubmit is working but for some reason the input value is undefined. I tried following some other examples but they were all forms in React components.
let SomeForm = (props) => {
let firstName = '';
const handleSubmit = (e) => {
e.preventDefault();
console.log(firstName);
}
return (
<div>
<form onSubmit={handleSubmit}>
<TextField
floatingLabelText="First Name"
floatingLabelFixed={true}
underlineStyle={styles.underlineStyle}
underlineFocusStyle={styles.underlineFocusStyle}
value={firstName}
/>
<input type="submit" value="Submit" />
</form>
</div>
)
}
SomeForm = connect()(SomeForm)
export default SomeForm
You need to add onChange to the TextField to handle the updates. And because SomeForm is a stateful component, you may need to use a class component instead of a stateless functional component.
class SomeForm extends React.Component {
state = {
firstName: ''
};
handleChange = (e, value) => {
this.setState({ firstName: value });
};
handleSubmit = (e) => {
e.preventDefault();
console.log(this.state.firstName);
};
render () {
return (
<div>
<form onSubmit={this.handleSubmit}>
<TextField
id="text-field-controlled"
floatingLabelText="First Name"
floatingLabelFixed={true}
underlineStyle={styles.underlineStyle}
underlineFocusStyle={styles.underlineFocusStyle}
value={this.state.firstName}
onChange={this.handleChange}
/>
<input type="submit" value="Submit" />
</form>
</div>
)
}
}
See the API and examples of TextField here: http://www.material-ui.com/#/components/text-field
You need function that you will throw in your TextField component and with onChange you can get value of input.
handleChange(e){
Console.log(e.target.value)
}
And in TextField
<TextField onChange={this.handleCahnge}/}
Or use refs
<TextField ref="textfield" />
And get value with this.refs.textfield.getValue()

Resources