redux toolkit state resets - javascript

I am stuck setting a state in react redux tool kit. My objective is to set the state by capturing some information from a form.
Store
import { createSlice } from '#reduxjs/toolkit'
export const SourceSlice = createSlice({
name: 'source',
initialState: {
name : "" ,
description:"",
version:"" ,
contact :"" ,
id:"",
} ,
reducers: {
addSource: (state ,action) => {
state.name = action.payload.name
state.description = action.payload.description
state.version = action.payload.version
state.contact = action.payload.contact
state.id = action.payload.name + "-" + action.payload.version
} ,
},
})
// Action creators are generated for each case reducer function
export const { addSource ,addExtract} = SourceSlice.actions
export default SourceSlice.reducer
Form
import { useDispatch } from 'react-redux'
import {addSource } from '../../Store/SourceSlice'
import React, {useState} from 'react'
const Source = () => {
const dispatch = useDispatch("")
const [name, setName] = useState('');
const [description, setDescription] = useState('');
const [version, setVersion] = useState('');
const [contact, setContact] = useState('');
const saveSourceDetails = () => {
const payload =
{
name : name,
description : description,
version: version ,
contact: contact
}
dispatch(addSource(payload))
};
const onDataChange = (event) => {
event.preventDefault();
if( event.target.name === "name"){
setName(event.target.value)
}
if( event.target.name === "description"){
setDescription(event.target.value)
}
if( event.target.name === "version"){
setVersion(event.target.value)
}
if( event.target.name === "contactPerson"){
setContact(event.target.value)
}
}
return (
<div>
<form className="ui form" onSubmit={saveSourceDetails}>
<div className="field">
<div className="Three fields">
<div className="field">
<input
type="text"
name="name"
value={name}
placeholder="Source Name"
onChange={onDataChange}
/>
</div>
<div className="field">
<input
type="text"
name="description"
value={description}
placeholder="Source Description"
onChange={onDataChange}
/>
</div>
<div>
<select
name="version"
multiple=""
className="ui fluid dropdown"
onChange={onDataChange}
>
<option value=""></option>
<option value="v1">v1</option>
<option value="v2">v2</option>
<option value="v3">v3</option>
</select>
</div>
<div className="field">
<input
type="text"
name="contactPerson"
value={contact}
placeholder="Contact Person"
onChange={onDataChange}
/>
</div>
<button className="ui button" type="submit">
+
</button>
</div>
</div>
</form>
</div>
);
};
export default Source;
Every time when i hit the button , the data is captured, send to redux the state is set for a second and the then state is reset to initial state. I am struggling to find out what makes the tool to reset everything. Any leads would help me.
PS: I am new to javascript and react

This function is the culprit. When you send the form, this gets called. You are not preventing the default event, so the page reloads, and you lose your Redux store.
const saveSourceDetails = () => {
const payload = {
name: name,
description: description,
version: version,
contact: contact
};
dispatch(addSource(payload));
};
Here's the corrected version:
const saveSourceDetails = (e) => {
e.preventDefault();
const payload = {
name: name,
description: description,
version: version,
contact: contact
};
dispatch(addSource(payload));
};

Related

react input form returns undefined

it updates only the lastly typed input box value in the state and other are undefined
i get this in console
Object { Name: undefined, Age: "123", City: undefined }
second time
Object { Name: undefined, Age: undefined, City: "city" }
Form.jsx
import React, {useState} from 'react';
const Form = (props) => {
const [formData, setFormData] = useState({ Name:'', Age:'', City:''});
const infoChange = e => {
const { name,value} = e.target;
setFormData({
[e.target.name]: e.target.value,
})
}
const infoSubmit = e =>{
e.preventDefault();
let data={
Name:formData.Name,
Age:formData.Age,
City:formData.City
}
props.myData(data);
}
return (
<div className="">
<form onSubmit={infoSubmit} autoComplete="off">
<div className="form-group mb-6">
<label className="">Name:</label>
<input type="text" onChange={infoChange} name="Name" value={formData.Name} className=""placeholder="Enter Name" />
</div>
<div className="form-group mb-6">
<label className="">City:</label>
<input type="text" onChange={infoChange} name="City" value={formData.City} className=""
placeholder="Enter Age" />
</div>
<button type="submit" className="">Submit</button>
</form>
</div>
);
};
export default Form;
App.jsx
this is App.jsx file, here i get the data prop and display it in console.log
import React from 'react';
import Form from './components/Form';
import Table from './components/Table';
const App = () => {
const create = (data) => {
console.log(data);
}
return (
<div className='flex w-full'>
<div className=''>
<Form myData={create} />
</div>
<div className=''>
<Table />
</div>
</div>
);
};
export default App;
You're stomping the previous state with the most recent change. If you want to preserve the existing state you have to include it in the update.
setFormData({
...formData,
[e.target.name]: e.target.value,
})
with react-hooks you need to set the entire object again.
const [formData, setFormData] = useState({ Name:'', Age:'', City:''});
const infoChange = e => {
const { name,value} = e.target;
setFormData({
// spread the current values here
...formData,
// update the current changed input
[name]: value,
})
or, even better IMHO. You have one state for each prop
const [name, setName] = useState('');
const [age, setAge] = useState('');
const [city, setCity] = useState('');
// ...
<input onChange={({target: {value}}) => setName(value)} />
<input onChange={({target: {value}}) => setAge(value)} />
<input onChange={({target: {value}}) => setCity(value)} />
Change this
const infoChange = e => {
const { name,value} = e.target;
setFormData({...formData
[e.target.name]: e.target.value,
})
}

how to clear all inputs in react div

import "./App.css";
import { useState } from "react";
import { useSelector, useDispatch } from "react-redux";
import { addUser} from "./features/Users";
function App() {
const dispatch = useDispatch();
const userList = useSelector((state) => state.users.value);
const [name, setName] = useState("");
const [username, setUsername] = useState("");
return (
<div className="App">
{" "}
<div className="addUser">
<input
type="text"
placeholder="Name..."
onChange={(event) => {
setName(event.target.value);
}}
/>
<input
type="text"
placeholder="Username..."
onChange={(event) => {
setUsername(event.target.value);
}}
/>
<button
onClick={() => {
dispatch(
addUser({
id: userList[userList.length - 1].id + 1,
name,
username,
})
);
}}
>
{" "}
Add User
</button>
</div>
);}
I am new to react and redux. After clicking the "Add User" button, new User data from inputs in the code will be added to the backend list. I want the values in input sections to be cleared after clicking the "Add User" button, but I don't know how to do.
you need to clear your state after click on submit button. for ex: set function like =>
const clearData = {
setName("")
setUsername("")
}
and pass the func to your onClick event.
onClick={clearData}
The following code will work perfectly fine.
Just assign value={name} and value={username} to both input types respectively and when you click Add User just clear the data in both the states.
import "./App.css";
import { useState } from "react";
import { useSelector, useDispatch } from "react-redux";
import { addUser} from "./features/Users";
function App() {
const dispatch = useDispatch();
const userList = useSelector((state) => state.users.value);
const [name, setName] = useState("");
const [username, setUsername] = useState("");
return (
<div className="App">
{" "}
<div className="addUser">
<input
type="text"
placeholder="Name..."
value={name}
onChange={(event) => {
setName(event.target.value);
}}
/>
<input
type="text"
placeholder="Username..."
value={username}
onChange={(event) => {
setUsername(event.target.value);
}}
/>
<button
onClick={() => {
setName("");
setUsername("");
dispatch(
addUser({
id: userList[userList.length - 1].id + 1,
name,
username,
})
);
}}
>
{" "}
Add User
</button>
</div>
);}
You can maintain a simple variable with list of form fields and can update the form state with the variable when you needed to clear form data. The below approach comes handy when you need to add additional fields as well.
import "./App.css";
import { useState } from "react";
import { useSelector, useDispatch } from "react-redux";
import { addUser} from "./features/Users";
const formFields = { name: '', username: '' };
function App() {
const dispatch = useDispatch();
const userList = useSelector((state) => state.users.value);
const [params, setParams] = useState(formFields)
const handleChange = (e) => {
const { name, value } = e.target;
setParams({ ...params }, ...{[name]: value});
}
const clearForm = () => setParams(formFields);
return (
<div className="App">
<div className="addUser">
<input
type="text"
placeholder="Name..."
value={params.name}
onChange={(e) => handleChange(e)}
/>
<input
type="text"
placeholder="Username..."
value={params.username}
onChange={(e) => handleChange(e)}
/>
<button
onClick={() => {
dispatch(
addUser({
id: userList[userList.length - 1].id + 1,
...params
})
);
clearForm();
}}
>
{" "}
Add User
</button>
</div>
</div>
)
}

Extra item being added in localStorage?

I am trying to build message component in react. Currently I just saving entered messages in localStorage but whenever I am pushing a message 2 rows get pushed in localStorage which should not happen. I have checked it but not able to get why this happening.
message comp
import React, { useState, useEffect } from "react";
interface IMessage {
user: string;
text: string;
}
export const Message = () => {
const [messages, setMessages] = useState<IMessage[]>([]);
const [message, setMessage] = useState("");
const [user, setUser] = useState("testuser");
useEffect(() => {
const fetchedMessages = JSON.parse(localStorage.getItem("messages") as any);
if (fetchedMessages) {
console.log("fetchedMessages=>", fetchedMessages);
}
}, [messages]);
const handleFormSubmit = (event: any) => {
event.preventDefault();
setMessages((messages) => {
const newData = [...messages, { text: message, user: user }];
let oldStorage =
JSON.parse(localStorage.getItem("messages") as any) || [];
const oldStorageN = [...oldStorage, { text: message, user: user }];
localStorage.removeItem("messages");
localStorage.setItem("messages", JSON.stringify(oldStorageN));
return newData;
});
setMessage("");
};
return (
<>
<div className="MessageContainer">
{messages.map((message) => {
return (
<div key={message.text + message.user}>
<div>
<strong>{message.user}</strong>
<div>{message.text}</div>
</div>
</div>
);
})}
</div>
<div>
<form onSubmit={handleFormSubmit}>
<div>
<input
type="text"
name="message"
onChange={(e) => {
setMessage(e.target.value);
}}
value={message}
/>
</div>
<div>
<input type="submit" value="send" />
</div>
</form>
</div>
</>
);
};
This is code link
https://stackblitz.com/edit/react-starter-typescript-qowlvq?file=components/Message.tsx
Note: on StackBlitz it's working fine, but on my machine it's adding two entries per message.

how to conditionally render the respond from an api

I want to get input from a user and compare it with the response I am getting from API, and conditionally render the information if it match or just show a sorry message,(the API only contain 1 set of a data object including 4 value) let me know what am I missing.
here is my code
import React, { useState } from "react";
import axios from "axios";
function Form() {
const [vatInput, setVatInput] = useState("");
const [responseVatState, setResponseVatState] = useState("");
const [responseCountryCodeState, setResponseCountryCodeState] = useState("");
const [result, setResult] = useState(false);
const handelVatState = (event) => {
setVatInput(event.target.value);
};
const closeModalHandler = () => {
setResult(false);
};
const onFormSubmit = (event) => {
event.preventDefault();
axios
.get("Some URL")
.then((response) => {
setResponseVatState(response.data.response.data.VATNumber);
setResponseCountryCodeState(response.data.CountryCode);
})
.catch((error) => {
console.log(error);
});
};
const inputCountryCode = vatInput.substring(0, 2);
const inputVatCode = vatInput.substring(2);
if (
inputCountryCode === responseCountryCodeState &&
inputVatCode === responseVatState
) {
setResult(true);
} else {
setResult(false);
}
return (
<div >
<h4>VAT Validator</h4>
<form onSubmit={onFormSubmit}>
<label className="text-muted">Please Enter A Vat Number:</label>
<input
type="text"
name="VatInput"
placeholder="Please Enter A Vat Number"
onChange={handelVatState}
/>
<br />
<input type="submit" value="Let'Go" />
</form>
<label className="text-muted">Result : </label>
{result ? (
<div>{vatInput}</div>
) : (
<div clicked={closeModalHandler}>
<span> Sorry !!! Please Insert corect VAT Number</span>
</div>
)}
</div>
);
}
export default Form;
and the error is
react-dom.development.js:14997 Uncaught Error: Too many re-renders. React limits the number of renders to prevent an infinite loop.
so I get the input from the user and set it with hooks, then with Axios call get my data, then I split the string with
const inputCountryCode = vatInput.substring(0, 2);
const inputVatCode = vatInput.substring(2);
to compare with the input I have, if it's the same then render the data if not just render the sorry message
You have a couple of issues, the main of which resulting in Uncaught Error: Too many re-renders. React limits the number of renders to prevent an infinite loop. is due to an infinite loop of component re-rendering, which you force by setting state directly in the function body.
More specifically, this code:
if (
inputCountryCode === responseCountryCodeState &&
inputVatCode === responseVatState
) {
setResult(true);
} else {
setResult(false);
}
force react to re-evaluate the component because you're changing its state by using setResult. When react starts rendering the new body it yet again encounters setResult which results in a new update and re-render which, as you see, leads to a never-ending loop.
Furthermore, you don't need to save the request response to the component state at all, as it is relevant just for the calculation, which is needed only in the form submit handler itself. So, you should ditch the
const [responseVatState, setResponseVatState] = useState("");
const [responseCountryCodeState, setResponseCountryCodeState] = useState("");
state variables altogether. The only state you need except the input value is the validation result.
Also, you have a typo: setResponseVatState(response.data.response.data.VATNumber); should be setResponseVatState(response.data.VATNumber);.
Try this:
import React, { useState } from "react";
import axios from "axios";
function Form() {
const [vatValue, setVatValue] = useState("");
const [isVatValid, setIsVatValid] = useState(false);
const handelVatState = (event) => {
setVatValue(event.target.value);
};
const closeModalHandler = () => {
setIsVatValid(false);
};
const onFormSubmit = (event) => {
event.preventDefault();
axios
.get("[URL]")
.then((response) => {
const inputCountryCode = vatValue.substring(0, 2);
const inputVatCode = vatValue.substring(2);
const { VATNumber, CountryCode } = response.data;
if (inputCountryCode === CountryCode && inputVatCode === VATNumber) {
setIsVatValid(true);
}
else {
setIsVatValid(false);
}
})
.catch((error) => {
console.log(error);
});
};
return (
<div >
<h4>VAT Validator</h4>
<form onSubmit={onFormSubmit}>
<label className="text-muted">Please Enter A Vat Number:</label>
<input
type="text"
name="VatInput"
placeholder="Please Enter A Vat Number"
onChange={handelVatState}
/>
<br />
<input type="submit" value="Let'Go" />
</form>
<label className="text-muted">Result : </label>
{isVatValid ? (
<div>{vatValue}</div>
) : (
<div clicked={closeModalHandler}>
<span> Sorry !!! Please Insert corect VAT Number</span>
</div>
)}
</div>
);
}
export default Form;
Also, I suppose <div clicked={closeModalHandler}> should be <div onClick={closeModalHandler}>?
EDIT:
Here is your solution after comments:
import React, { useState } from "react";
import axios from "axios";
function Form() {
const [vatValue, setVatValue] = useState("");
const [isVatValid, setIsVatValid] = useState(null);
const handelVatState = (event) => {
setVatValue(event.target.value);
};
const closeModalHandler = () => {
setIsVatValid(null);
};
const onFormSubmit = (event) => {
event.preventDefault();
axios
.get("https://vat.erply.com/numbers?vatNumber=BG999999999")
.then((response) => {
const inputCountryCode = vatValue.substring(0, 2);
const inputVatCode = vatValue.substring(2);
const { VATNumber, CountryCode } = response.data;
if (inputCountryCode === CountryCode && inputVatCode === VATNumber) {
setIsVatValid(true);
}
else {
setIsVatValid(false);
}
})
.catch((error) => {
console.log(error);
});
};
const getResultRepresentation = () => {
if (isVatValid === null) {
return null;
}
if (isVatValid) {
return (
<>
<label className="text-muted">Result: </label>
<div>{vatValue}</div>
</>
);
}
else {
return (
<div onClick={closeModalHandler}>
<span> Sorry !!! Please Insert corect VAT Number</span>
</div>
);
}
}
return (
<div >
<h4>VAT Validator</h4>
<form onSubmit={onFormSubmit}>
<label className="text-muted">Please Enter A Vat Number:</label>
<input
type="text"
name="VatInput"
placeholder="Please Enter A Vat Number"
value={vatValue} // <= missing
onChange={handelVatState}
/>
<br />
<input type="submit" value="Let'Go" />
</form>
{getResultRepresentation()}
</div>
);
}
export default Form;
And here is a CodeSandbox to test it out.

How can I change form input value in React and Redux?

I'm trying to handle changes in inputs. I know how to do this in React, but now I'm using also Redux and I have no idea how to change values in inputs. When I try to type letters nothing change. Can you tell me what should I do in handleChange and handleSelect functions? Or maybe there is any other solution? Here's my code
import React, { Component } from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { updateSensor, getSensorData } from '../actions/sensors';
class EditSensorPage extends Component {
static propTypes = {
sensorName: PropTypes.string.isRequired,
sensorCategory: PropTypes.string.isRequired,
updateSensor: PropTypes.func.isRequired,
getSensorData: PropTypes.func.isRequired
}
handleChange = e => {
// this.setState({ sensorName: e.target.value })
}
handleSelect = e => {
// this.setState({ sensorCategory: e.target.value })
}
handleSubmit = e => {
e.preventDefault();
console.log("name: " + this.state.name, "category: " + this.state.category)
const id = this.props.match.params.id;
const sensorName = this.props.sensorName;
const sensorCategory = this.props.sensorCategory;
// const { sensorName, sensorCategory } = this.state;
const sensor = { sensorName, sensorCategory };
this.props.updateSensor(id, sensor);
}
componentDidMount() {
const id = this.props.match.params.id;
this.props.getSensorData(id)
}
render() {
return (
<div className="col-md-6 m-auto">
<div className="card card-body mt-5">
<h2 className="text-center">Edytuj czujnik</h2>
<form onSubmit={this.handleSubmit}>
<div className="form-group">
<label>Nazwa</label>
<input
type="text"
className="form-control"
name="sensorName"
onChange={this.handleChange}
value={this.props.sensorName}
/>
</div>
<div className="form-group">
<label>Kategoria</label>
<select className="form-control" onChange={this.handleSelect} value={this.props.sensorCategory}>
<option></option>
<option value="temperature">Czujnik temperatury</option>
<option value="humidity">Czujnik wilgotności</option>
</select>
</div>
<div className="form-group">
<button className="btn btn-primary">Potwierdź</button>
</div>
</form>
</div>
</div>
);
}
}
const mapStateToProps = state => ({
sensorName: state.sensors.sensorName,
sensorCategory: state.sensors.sensorCategory,
})
export default connect(mapStateToProps, { updateSensor, getSensorData })(EditSensorPage);
Assuming you set up the redux actions/function correctly, all you need is the dispatch to fire the redux action.
basically you want to do:
const mapDispatchToProps = dispatch => {
return {
updateSensor: data => dispatch(updateSensor(data))
}
}
Then in your handle Select/handle change function:
/* this would varies depends on how updateSensor is defined. Just make sure
the function `updateSensor` is returning an action such as
{ type: 'UPDATE_SENSOR', payload: value }
*/
handleChange = event => {
this.props.updateSensor({sensorName: event.target.value})
}
You might find this question is useful when trying to get the insight into dispatch and mapDispatchToProps:
What is mapDispatchToProps?

Categories