Maintaining checkbox value on local Storage React - javascript

I am trying to save the value of checkboxes in local storage, so when the user reloads the page, they remain checked/unchecked.
I have an "isChecked" state and a handleOnChange function.
What im trying to do is store the value on the state, and every time the onChange fuction runs, i set the 'checkbox' key on local storage to the value of the checkbox.
this is what my component looks like
import React from "react";
import { useState, useEffect } from "react";
const Pdf = (props) => {
const [shown, setShown] = useState(false);
const [isChecked, setIsChecked] = useState(localStorage.getItem('checkbox') === 'true');
const handleOnChange = (e) => {
setIsChecked(localStorage.getItem('checkbox'));
localStorage.setItem('checkbox',`${e.target.checked}`)
}
const toggle = () => {
setShown((prevState) => !prevState);
alert(isChecked)
};
return (
<div className="pdfContainer row container justify-content-center">
<section className="justify-content-center">
<h1 className="row justify-content-center h1--style">
Κεφάλαιο {props.id}
</h1>
<p className="row justify-content-center p--style">{props.info}</p>
</section>
<button onClick={toggle} className=" shadow button--style">
Μάθημα {props.id}
</button>
{shown && <embed className=" pdf" src={props.pdf} />}
<div className="pdfChecked input-group-text input-group ">
<input
type="checkbox"
id='pdfchecked'
name="pdfChecked"
value='1'
checked={isChecked}
onChange={handleOnChange}
/> <label className="input--label"> Διάβασα το κεφάλαιο!</label>
</div>
</div>
);
};
export default Pdf;
I understand that this is very buggy, and very much not how you're supposed to do it. I found the local storage concept hard to grasp as a beginner, and i have tried many ways to make this work. As of now, it kinda works, meaning when i reload the page it stays the same, but i have to click on the checkbox multiple times! SO buggy. Any help, especially letting me know why my thought process is wrong, would be appreciated!

Related

How to refetch properly an API request after an event occurred?

i'm a react beginner and I'm struggling with the refresh of the components.
In this case, I have a GET request to an API triggering in a useEffect hook with no dependencies on my App.js. Of course, this is working just fine when my app just starts. However, I need it to trigger again after certain events ocurre, like an Onclick event in a button, and a OnSubmit event in a form, in order to re render the updated table component where the API data is displayed.
What is the best way to do this?
I thought about just calling the fetch function again whenever I need to update the data, but I don't know if that's the way to go.
Then, I currently have this workaround function to force the reload of the entire page after the events trigger, but i'm pretty sure this is not proper either:
const refresh = () =>{
window.location.reload(false);
}
I've been also tweaked the dependencies in the use effect (where the fetch happens) a little bit, because I'm feeling like the solution is there, but I had only bad results, like infinite loops.
Finally guys, I'll post an overview pic of my App code. Have in mind that I need to do the refresh in the next components: OrdenPago y Grid.
import { useState, useEffect } from 'react';
import { OrdenPago } from './OrdenDePago';
import EstadoCvus from './EstadoCvus';
import Grid from './Grid';
import axios from 'axios';
export const App = () => {
const [ops, setOps] = useState({ ordenesPago: [] });
useEffect( () => {
axios.get("http://cpawautojava:1400/consultaOrdenesPago")
.then(response => {
setOps(response.data);
console.log(response.data);
}).catch((error) => { console.log(error) })
}, [])
return (
<div className="container">
<div className='row'>
<div className='col-12'>
<div className='text-white py-2' style={{ backgroundColor: "#414BB2", height: "40px" }} >
<h1 className='text-center lead fw-bold'>Gestión de OPs</h1>
</div>
</div>
</div>
<div className='row mt-3' >
<div className='col-6 d-flex justify-content-center'>
<OrdenPago />
</div>
<div className='col-6 form1' >
<EstadoCvus />
</div>
</div>
<div className='row'>
<div className='col-12' >
<Grid ops={ops} />
</div>
</div>
</div>
);
}
Thanks in advance for your help.
Rodrigo.

MaxListenersExceedWarning: Possible EventEmitter memory leak detected

A similar issue to the following however I cannot seem to code my way out of it.
Link to similar issue
Possible EventEmitter memory leak detected without EventEmiter
Please find code underneath:
I suspect that the error handling in the 'input onchange' of CreateThread component are causing the issues but at this point I am really not sure about anything anymore. That being said it could be that a connect button in the header could be the culprit being that the console hints at the 'accountChanged Listeners' however I do not recall adding anything unusual. (Adding image for clarity)
Could anyone please shine their light on this issue?
I am already hugely appreciative!
CreateThread.js component
import { abi, contractAddresses } from "../constants";
import { useMoralis } from "react-moralis";
import { useEffect, useState } from "react";
export default function startThread() {
const { chainId: chainIdHex, isWeb3Enabled } = useMoralis();
const chainId = parseInt(chainIdHex);
const threadAddress =
chainIdHex in contractAddresses ? contractAddresses[chainId][0] : null;
const [threadtitle, setthreadtitle] = useState("");
const [threadpost, setthreadpost] = useState("");
const { runContractFunction: createThread } = useWeb3Contract({
abi: abi,
contractAddress: threadAddress,
functionName: "createThread",
params: { _threadTitle: threadtitle, _threadPost: threadpost }, //these parameters should come from the input boxes (document.getElementById("threadtitle").value, etc.)
msgValue: {},
});
async function Update() {
const response = await createThread();
console.log(response);
}
useEffect(() => {
if (isWeb3Enabled) {
}
}, []);
return (
<div>
<div className="bg-slate-400 w-screen h-96 py-4 px-2">
<div>Threadtitle</div>
<input
className=" w-11/12"
id="threadtitle"
onChange={(e) => setthreadtitle(e.target.value)}
></input>
<div>Threadpost</div>
<input
className=" w-11/12 h-24"
id="threadpost"
onChange={(e) => setthreadpost(e.target.value)}
></input>
<div className="py-4">
<button
className="bg-blue-500 hover:bg-blue-400 text-white font-bold py-2 px-4 border-b-4 border-blue-700 hover:border-blue-500 rounded"
onClick={Update}
>
Create Thread
</button>
</div>
</div>
</div>
);
}
Header.js
import { ConnectButton } from "web3uikit";
export default function Header() {
return (
<div className="p-5 border-b-2 flex flex-row bg-slate-400">
<h1 className="py-4 px-4 font-blog text-3xl">
deAgora - Forum for the people, by the people
</h1>
<div className="ml-auto py-2 px-4">
<ConnectButton moralisAuth={false}></ConnectButton>
</div>
</div>
);
}
The issue has seemingly been solved by not constantly rerendering the component which includes the web3uikit connectbutton (which in the above case is the header). I get the sense that on every render the connectbutton adds a listener every time the connectbutton is rendered and does not remove that listener on rerender (someone more with more knowledge on the matter should confirm tho).
I have moved the header out of the routing scheme to always show and therefore it does not rerender on every action performed in the front end (like browsing through the navbar). This seems to have solved the issue.

Warning: A component is changing a controlled input to be uncontrolled. This is likely caused by the value changing from a defined to undefined,

I'm a newbie to React.js and I face with a strange error that I can't figure out why that's happening, I searched but and didn't find any solutions.
Here is is my component codes:
import React, { useState } from "react";
const AddMovie = () => {
const [movie, setMovie] = useState({ title: "", director: "" });
const onChange = (value, filed) => {
setMovie({
[filed]: value,
});
};
const onSubmit = (e) => {
e.preventDefault();
console.log(movie.title, movie.director);
setMovie({ title: "", director: "" });
};
return (
<div>
<form className="flex -mx-2" onSubmit={onSubmit}>
<div className="ml-2">
<input
type="text"
className="border p-2 rounded-md focus:outline-none"
placeholder="Movie Title"
value={movie.title}
onChange={(e) => onChange(e.target.value, "title")}
required
/>
</div>
<div className="mx-2">
<input
type="text"
className="border p-2 rounded-md focus:outline-none"
placeholder="director"
value={movie.director}
onChange={(e) => onChange(e.target.value, "director")}
required
/>
</div>
<div>
<button
type="submit"
className="h-full border rounded-md px-4 text-white bg-gray-900"
>
Add Movie
</button>
</div>
</form>
</div>
);
};
export default AddMovie;
and the error that I face with it is this: (i referred to DOC and I read this section but it didn't work as well)
react_devtools_backend.js:3973 Warning: A component is changing a controlled input to be uncontrolled. This is likely caused by the value changing from a defined to undefined, which should not happen. Decide between using a controlled or uncontrolled input element for the lifetime of the component. More info: https://reactjs.org/link/controlled-components
so what is the problem?
I have done this way of binding (object syntax) in Vue.js a lot of times but I haven't been facing this once, so is a bit queer for me.
The error is due to value={movie.director} being undefined once you change your movie title. That happens because you miss use the setter API,
With hooks (READ THE NOTE), the state setter does not merge state as in class component, change it to:
// field = 'title'
setMovie(prevState => ({...prevState, [field]: value }))
Unlike the setState method found in class components, useState does not automatically merge update objects.
Unlike the setState method found in class components, useState does not automatically merge update objects.

ReactJS: Cannot update during an existing state transition (such as within `render`). Render methods should be a pure function of props and state

Hello iam newbie in ReactJS, I'm using a library react-bootstrap4-form-validation to validate my form. From the documentation there are the function that use to reset the form validation. From the documentations there are example to reset the form validation using triggering button onClick, like this. And for a condition, i need to reset the validation, but not when triggering button onClick, but when the props from parent component is change. Because of these needs I also created a function (useCompare) that is used to compare the props received from the parent component.
In short, I want to reset my form, when the props received from the parent component changes, and the code is as shown below.
import React, { useRef } from "react";
import { ValidationForm, TextInput } from 'react-bootstrap4-form-validation';
import { useCompare } from '../../services/compare-props';
function TestForm({ form }) {
const formRefs = useRef();
const handleSubmit = (e, formData, inputs) => {
e.preventDefault();
console.log(formData)
}
if ( !useCompare(form) ) {
resetForm()
}
function resetForm() {
let formRef = formRefs.current;
formRef != null ? formRef.resetValidationState(true) : null;
}
return (
<div className="row justify-content-center">
<div className="col-md-6 col-sm-10">
<div className="shadow-sm p-3 mb-5 bg-white rounded border">
<h6>{form.labelForm}</h6>
<hr />
<ValidationForm onSubmit={handleSubmit} id="form-test" ref={formRefs}>
{form.field.map(function (fields, index) {
return (
<div className="row form-group mb-1" key={index}>
<div className="col-lg-4 col-sm-4 col-md-4">{fields.label}</div>
<div className="col-lg-8 col-sm-8 col-md-8">
<TextInput
type={fields.type}
className="form-control"
name={fields.name}
autoComplete="off"
required
{...(form.formType == 'add' && fields.name == 'brand_code' ? {minLength : "4"} : {})}
/>
</div>
</div>
);
})}
<button type="submit" className="btn btn-danger">
Save
</button>
<button type="button" className="btn btn-warning" onClick={() => resetForm()}>
Reset Form
</button>
</ValidationForm>
</div>
</div>
</div>
);
}
export default TestForm;
The code above works fine when the props received from the parent component doesn't change, and when I try to reset the form via onClick trigger button, it works fine too. But when I want to reset the form when the props of the parent component changes, it generates an error like this:
Warning: Cannot update during an existing state transition (such as within render). Render methods should be a pure function of props and state
Can anyone help me solve this problem? I am very grateful beforehand.
Try moving useCompare check to a side effect:
useEffect( () => {
if ( !useCompare(form) ) {
resetForm()
}
}, [useCompare, form, resetForm] )
You will likely have to wrap resetForm in a useCallback hook.
This useEffect will run every time form changes, and placing it here should prevent the 'update during render' issue.

React - selected value is not displayed after refreshing page

So, I'm using react-select to let the user pick a choice from a list of options. It's supposed to update on-change. I've verified that the selected option is indeed being updated into the database, and the input is being recognized by React upon checking it in the React chrome tools. What's puzzling is how it doesn't get displayed after refreshing the page.
class ContractBasicForm extends React.Component {
constructor (props) {
super(props)
this.state = {
contractingEntity: props.contracting_entity
}
componentWillReceiveProps(nextProps) {
this.setState({
contractingEntity: nextProps.contracting_entity
})
}
autoSetState = (newState) => {
this.setState(newState)
this.props.formSubmit()
}
render () {
return(
<div className="container-fluid">
<section className="row ml-2 mr-2 mt-2">
<article className="col-12 side-modal-form">
<SelectInput
header="Contracting Entity"
name="contract[contracting_entity]"
options={this.props.contracting_entity_opts}
value={this.state.contracting_entity}
userCanEdit={this.props.user_can_edit}
multi={false}
onChange={(e) => {
this.autoSetState({contracting_entity: e.value})
}}
/>
</article>
</section>
</div>
)
}
}
I have another input called Stage which is very similar to ContractingEntity, but its value is displayed after refreshing the page:
<SelectInput
header="Stage"
name="contract[stage]"
options={this.props.stage_opts}
value={this.state.stage}
userCanEdit={this.props.user_can_edit}
multi={false}
onChange={(e) => {
this.autoSetState({stage: e.value})
}}
/>
React app state will be initialised on page refresh. You need to persist such data in localStorage if you want to keep it after page refresh. This is considered as anti-pattern in react and it is recommended not to use this unless it becomes necessity.
I hope this made things clear for you.

Categories

Resources