I have defined a context Transaction which takes an object and a function.
In AppProvider Transaction.Provider is returned.
The code is of GlobalState.tsx file:
import { createContext, useState } from "react";
export interface IProviderProps {
children?: any;
}
type Cat = {
id: number;
text: string;
amount: number;
}
type Ca =Cat[]
export const initialState = {
state: [
{id:4, text:'hi', amount:234},
{id:3, text:'hd', amount:-234},
{id:1, text:'hs', amount:34}
],
setState: (state: Ca) => {}
}
console.log(initialState.state)
export const Transaction = createContext(initialState);
export const AppProvider = (props: IProviderProps) => {
const [state, setState] = useState(initialState.state);
console.log(state);
return <Transaction.Provider value={{state, setState}}>{props.children}</Transaction.Provider>;
};
In App.tsx I have passed the Provider:
import React, { useState } from 'react';
import './App.css';
import { Header } from "./Components/Header";
import { Balance } from './Components/Balance';
import { IncomeExpense } from "./Components/Income_Expense";
import { TransactionHistory } from "./Components/TransactionHistory";
import { AddTransaction } from "./Components/AddTransaction";
import { AppProvider } from './Context/GlobalState'
function App() {
const [islit, setlit] = useState(true);
return (
<AppProvider>
<div className={`${islit? '': 'dark'} body`}>
<Header islit={islit} setlit={setlit} />
<div className="container">
<Balance />
<IncomeExpense />
<TransactionHistory />
<AddTransaction />
</div>
</div>
</AppProvider>
);
}
export default App;
I am trying to change 'state' with 'setState' but it is not working:
import React, { useState, useContext } from 'react';
import { Transaction} from '../Context/GlobalState';
export const AddTransaction = () => {
const initialState = useContext(Transaction);
const [Incexp, setIncExp] = useState('income');
const [text, settext] = useState('');
const [amount, setamount] = useState(0);
const transactions = initialState.state;
const settransaction = initialState.setState;
function Addition(e: any) {
e.preventDefault();
settext('');
setamount(0);
transactions.push({id:Math.floor(Math.random() * 100000000), text:text, amount:Incexp==='income'? +amount: -amount})
settransaction(transactions);
console.log(transactions);
}
return (
<div>
<h3>Add Transaction</h3>
<form onSubmit={Addition}>
<label htmlFor="description">Text</label>
<input type="text" id="description" placeholder="Enter description..." value={text} onChange={(e) => { settext(e.target.value) }} required />
<label htmlFor="amount">Amount</label>
<input type="number" id="amount" placeholder="Enter Amount..." value={amount === 0 ? '' : amount} onChange={(e) => { setamount(parseInt(e.target.value)) }} required />
<div className="Inc-Exp">
<div>
<input type="radio" id="income" name="balance" defaultChecked onClick={()=>{setIncExp('income')}}/>
<label htmlFor="income" className="inc-col">Income</label>
</div>
<div>
<input type="radio" id="expense" name="balance" onClick={()=>{setIncExp('expense')}}/>
<label htmlFor="expense" className="exp-col">Expense</label>
</div>
</div>
<input className="btn" type="submit" value="Addtransaction" />
</form>
</div>
)
}
Another child component:
import React, { useContext } from 'react';
import { Transaction } from '../Context/GlobalState';
export const Balance = () => {
const initialState = useContext(Transaction);
const transactions = initialState.state;
var total=0;
transactions.map((transaction) => total+=transaction.amount)
return (
<div>
<h4>Your Balance</h4>
<h1 className={`${total > 0 ? 'plus' : ''} ${total < 0 ? 'minus' : ''}`}>${total}</h1>
</div>
)
}
Every time I click on a button Add Transaction. I want it to update state. but it is not updating.
The state is not update because you are not changing the reference of the object transactions, do it like below
function Addition(e: any) {
e.preventDefault();
settext('');
setamount(0);
settransaction([...transactions,{id:Math.floor(Math.random() * 100000000), text:text, amount:Incexp==='income'? +amount: -amount} ]);
console.log(transactions);
}
In this case the object you pass to settransaction will have a new reference the react will update the state
Please change setState to a callback variant setState((previousState) => {...}) as:
function Addition(e: any) {
e.preventDefault();
settext('');
setamount(0);
transactions.push({id:Math.floor(Math.random() * 100000000), text:text, amount:Incexp==='income'? +amount: -amount})
settransaction(transactions);
console.log(transactions);
}
to
function Addition(e: any) {
e.preventDefault();
settext('');
setamount(0);
settransaction((prevState) => {
return prevState.push({id:Math.floor(Math.random() * 100000000), text:text, amount:Incexp==='income'? +amount: -amount});
});
}
The console.log may not show updated value, as re-render would be required to get updated context value.
But after context update a re-render would going to be trigger by react, and thus the component responsible to show updated state will eventually display the updated state.
Related
I am working with Reactjs and nextjs,Right now i am trying to get input type text value but right now i am not getting any value(name is empty during alert), here is my current code
import dynamic from 'next/dynamic';
import React, { FormEventHandler, useRef } from 'react';
import { useEffect, useState } from "react";
import axios from 'axios';
export default function Testform() {
const [state, setState] = useState({ name: '' });
const [Name, setName] = useState('');
const handleChange = (event:any) => setState({...state, name: event.target.value })
const submitHandler: FormEventHandler<HTMLFormElement> = async (event) => {
event.preventDefault();
const name = Name;
alert('name is '+ name);
}
return (
<form className="forms-sample" onSubmit={submitHandler}>
<div className='flex-dvs'>
<div className="form-group">
<h3>Blog title</h3>
<input type="text"
className="form-control"
id="exampleInputName1"
placeholder="Title"
name="name"
value={state.name}
onChange={handleChange}
/>
</div>
</div>
<div className='save-btn text-right'>
<button className='btn btn-primary mr-2'>Save</button>
</div>
</form>
)
}
You are setting the state variable. So use state.name instead of Name
const name = state.name;
i want to pass a prop from one(App.jsx) component to other component(form.jsx) in state hooks
App.jsx
import React, {useEffect, useState} from 'react';
import Form from './components/Form';
import Table from './components/Table';
import axios from 'axios';
const App = () => {
const [data, setData] = useState({data:[]});
const [editData, setEditData] = useState([]);
const create = (data) => {
axios.post('http://localhost:5000/info',data).then((res) =>{
getAll();
})
}
useEffect(() =>{
getAll();
},[])
const getAll = () =>{
axios.get("http://localhost:5000/info").then((response) =>{
setData({
data:response.data
})
})
}
const update = event =>{
setEditData(data)
console.log(data); // THIS "data" is the prop that i need to pass to Form.jsx component
}
return (
<div>
<div>
<Form myData={create} editForm={editData} />
</div>
<div>
<Table getData={data} edit={update} />
</div>
</div>
);
};
export default App;
i want that "data" value form App.jsx component as props in this Form.jsx component
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({
...formData,
[name]: value,
})
}
const infoSubmit = e =>{
e.preventDefault();
let data={
Name:formData.Name,
Age:formData.Age,
City:formData.City
}
props.myData(data);
}
const componentWillReceive = (props) => { // i want the props data here
console.log(props.data); // in class component they use componentWillReceiveRrops ,
} // is there any alternative for function based component to receive props?
return (
<div>
<form onSubmit={infoSubmit} autoComplete="off">
<div>
<label>Name:</label>
<input type="text" onChange={infoChange} name="Name" value={formData.Name} placeholder="Enter Name" />
</div>
<div>
<label>City:</label>
<input type="text" onChange={infoChange} name="City" value={formData.City}
placeholder="Enter City" />
</div>
<div>
<label>Age:</label>
<input type="text" onChange={infoChange} name="Age" value={formData.Age} placeholder="Enter Age" />
</div>
<button type="submit">Submit</button>
</form>
</div>
);
};
export default Form;
i have commented the area of problem within the code , you can ignore the return () block of code.
Sorry for silly questions but THANKYOU Very Much !!! in advance
Use the following code in Form.jsx, the useEffect will listen the change of props.data and update the value
useEffect(() => {
setFormData(props.data);
},
[props.data]);
For more information, you may check the following answer
https://stackoverflow.com/a/65842783/14674139
In my project using react-hook-form to update and create details. There is an issue in the update form, the values are not updating properly, and the code
countryupdate.tsx
import React from 'react'
import { useQuery } from 'react-query'
import { useParams } from 'react-router-dom'
import { useCountryUpdate } from '../api/useCountryUpdate'
import { getDetails, useDetails } from '../api/useDetails'
import { CountryCreateUpdateForm } from '../forms/createupdateForm'
interface data{
id: string,
name: string
}
export const CountryUpdatepage = () => {
const { dataId }: any = useParams()
const { data, isLoading, isError } = useQuery(['details', dataId], () => getDetails(dataId), {
enabled: !!dataId,
});
const { mutateAsync } = useCountryUpdate();
const onFormSubmit = async() =>{
console.log("mutate", {...data})
await mutateAsync({...data, dataId})
}
return (
<div>
<h3>Update Details</h3>
<CountryCreateUpdateForm defaultValues={data} onFormSubmit={onFormSubmit} isLoading={undefined}/>
</div>
)
}
Here, when console the value inside onFormSubmit, it shows the same data in the previous state
createupdateform.tsx
import { useState } from "react"
import { useCountryCreate } from "../api/usecountrycreate"
import { useForm } from "react-hook-form"
export const CountryCreateUpdateForm = ({ defaultValues, onFormSubmit, isLoading }: any) => {
// console.log("name", defaultValues.data.name)
const { register, handleSubmit } = useForm({ defaultValues:defaultValues?.data });
const onSubmit = handleSubmit((data) => {
onFormSubmit(data)
})
return (
<form onSubmit={onSubmit}>
<div>
<label>Name</label>
<input {...register('name')} type="text" name="name" />
</div>
<button type="submit" >submit</button>
</form>
)
}
I am a beginner in react typescript, Please give me suggestions to solve this problem.
in countryupdate.tsx
the data is undefined at the beggining, so defaultValue of form is not updated after that;
it should help:
return (
<div>
<h3>Update Details</h3>
{data?.data && <CountryCreateUpdateForm defaultValues={data} onFormSubmit={onFormSubmit} isLoading={undefined}/>
}
</div>
)
I have been unable to setState on props I keep getting
TypeError: props.setState is not a function
I'm trying to implement a search function
const HeroComp = (props) => {
let handleSearchSubmit = (e) => {
props.setState({searchValue: e.target.value});
}
return <div className='heroComp' >
<form action="" >
<input type="text" placeholder='search cartigory' onChange={handleSearchSubmit} />
</form>
</div>
}
export default HeroComp;
When I console.log(props) I get
{searchValue: ""}
searchValue: ""
__proto__: Object
This is the parent component
import images from '../data/images'; //the file from which i'm importing images data
class HomePage extends React.Component{
constructor(){
super();
this.state = {
images,
searchValue: ''
}
}
render(){
const {images , searchValue} = this.state;
const filteredImage = images.filter(image => image.cartigory.toLowerCase().includes(searchValue));
return(
<div >
<HeroComp searchValue={ searchValue } />
<GalleryComp filteredImage={filteredImage} />
</div>
)
}
}
export default HomePage;
I know this should be easy but I just can't see the solution .
How about this?
useEffect(() => {
// set the current state
setSearchValue(props.searchValue)
}, [props]);
Functional component dont have state, but you can use reactHooks:
import React, { useState } from 'react';
const HeroComp = (props) => {
let [searchValue, setSearchValue] = useState();
let handleSearchSubmit = (e) => {
setSearchValue(e.target.value);
}
return <div className='heroComp' >
<form action="" >
<input type="text" placeholder='search cartigory' onChange={handleSearchSubmit} />
</form>
</div>
}
export default HeroComp;
I am trying to make a redux pattern with useContext and useReducer. I create a component that creates a context (a reducer), and I also have the initial values. I declare my reduction with the foregoing, and return to the child component that is being provided by the values of my Reducer.
Then in the next image I have a view that will render a component that makes a form and that is wrapped in the ExpenseReducer component so that it has the values of my reduce.
In the form, I import the context and try to use the dispatch, but I get an error like "undefined"
My Code
import React from "react";
//Context
export const ExpenseContext = React.createContext();
// Reducer
const reducer = (state, action) => {
switch (action.type) {
case "HANDLE_SUBMIT":
return alert("Guardado");
default:
return state;
}
};
// Valores iniciales
const initialExpenses = [
{ id: "37c237f8-3004-4f69-9101-62f59ba4ce09", charge: "carne", amount: "20" },
{
id: "32bf7455-61c8-48d5-abe1-a38c93dcf1c8",
charge: "internet",
amount: "20"
},
{ id: "7e22c2e8-7965-41fe-9f39-236f266c9f24", charge: "ca", amount: "1" }
];
function ExpenseReducer({ children }) {
const [expenses, dispatch] = React.useReducer(reducer, initialExpenses);
return (
<ExpenseContext.Provider value={{ expenses, dispatch }}>
{children}
</ExpenseContext.Provider>
);
}
export default ExpenseReducer;
import React from "react";
// Components
import ExpenseForm from "../components/ExpenseForm";
import ExpenseReducer from "../reducers/ExpenseReducer/ExpenseReducer";
function ExpenseNew() {
return (
<ExpenseReducer>
<ExpenseForm />
</ExpenseReducer>
);
}
import React, { useContext } from "react";
import "./ExpenseForm.scss";
import { ThemeContext } from "../App";
import { ExpenseContext } from "../reducers/ExpenseReducer/ExpenseReducer";
const ExpenseForm = () =>
// {
// // edit,
// // charge,
// // amount,
// // handleCharge,
// // handleAmount,
// // handleSubmit
// }
{
// Theme
const { theme } = useContext(ThemeContext);
const { expenseContext } = useContext(ExpenseContext);
return (
<form
className="form"
onSubmit={expenseContext.dispatch("HANDLE_SUBMIT")}
>
<div className="form-group">
{/*To conect the value with the variable */}
<input
type="text"
className={`${theme} form-control`}
// id="charge"
// name="charge"
// placeholder="Gasto"
// value={charge}
// onChange={handleCharge}
/>
</div>
<div className="form-group">
{/*To conect the value with the variable */}
<input
type="number"
className={`${theme} form-control`}
// id="amount"
// name="amount"
// placeholder="Cuanto"
// value={amount}
// onChange={handleAmount}
/>
<textarea
placeholder="Descripción"
className={`${theme} form-control`}
id=""
cols="30"
rows="10"
></textarea>
</div>
<button type="submit" className={`btn ${theme}`}>
{true ? "Editar" : "Guardar"}
</button>
</form>
);
};
export default ExpenseForm;
According to the docs:
Don’t forget that the argument to useContext must be the context object itself:
Correct: useContext(MyContext)
Incorrect: useContext(MyContext.Consumer)
Incorrect: useContext(MyContext.Provider)
Your reducer is returning the provider, not the context object. Hence it results in expenseContext being undefined.