Issue in react context api - javascript

Facing issues in react context api, getting undefined while transferring anything using context api.
getting this error, getting undefined when sending functions through context api.
*** Context.js
import React, { useReducer, createContext } from "react";
import contextReducer from "./contextReducer";
const initialState = [];
export const ExpenseTrackerContext = createContext(initialState);
export function Provider({ children }) {
const [transactions, dispatch] = useReducer(contextReducer, initialState);`enter code here`
const deleteTransaction = (id) =>
dispatch({ type: "DELETE_TRANSACTION", payload: id });
const addTransaction = (transaction) =>
dispatch({ type: "ADD_TRANSACTION", payload: transaction });
return (
<ExpenseTrackerContext.Provider
value={{
deleteTransaction,
addTransaction,
transactions,
}}
>
{children}
</ExpenseTrackerContext.Provider>
);
}***
getting undefined in this file while using the function in this file Form.js > and getting error addTransaction is not a function
*** Form.js
import React, { useState, useContext } from "react";
import {
TextField,
Typography,
Grid,
FormControl,
InputLabel,
Select,
MenuItem,
Button,
} from "#material-ui/core";
import { ExpenseTrackerContext } from "../../context/context";
import { v4 as uuidv4 } from "uuid";
import useStyles from "./styles";
const initialState = {
amount: "",
category: "",
type: "Income",
date: new Date(),
};
const Form = (props) => {
const classes = useStyles();
const [formData, setFormData] = useState(initialState);
// console.log(useContext(ExpenseTrackerContext));
const { addTransaction } = useContext(ExpenseTrackerContext);
console.log("context: " + ExpenseTrackerContext.displayName);
console.log("add: " + typeof addTransaction);
const createTransaction = () => {
const transaction = {
...formData,
amount: Number(formData.amount),
id: uuidv4(),
};
addTransaction(transaction);
setFormData(initialState);
};
return (
<Grid container spacing={2}>
<Grid item xs={12}>
<Typography align="center" variant="subtitle2" gutterBottom>
...
</Typography>
</Grid>
<Grid item xs={6}>
<FormControl fullWidth>
<InputLabel>Type</InputLabel>
<Select
value={formData.type}
onChange={(e) => setFormData({ ...formData, type: e.target.value })}
>
<MenuItem value="Income">Income</MenuItem>
<MenuItem value="Expense">Expense</MenuItem>
</Select>
</FormControl>
</Grid>
<Grid item xs={6}>
<FormControl fullWidth>
<InputLabel>Category</InputLabel>
<Select
value={formData.category}
onChange={(e) =>
setFormData({ ...formData, category: e.target.value })
}
>
<MenuItem value="business">Business</MenuItem>
<MenuItem value="Salary">Salary</MenuItem>
</Select>
</FormControl>
</Grid>
<Grid item xs={6}>
<TextField
type="number"
label="Amount"
fullWidth
value={formData.amount}
onChange={(e) => setFormData({ ...formData, amount: e.target.value })}
/>
</Grid>
<Grid item xs={6}>
<TextField
type="date"
label=" "
fullWidth
value={formData.date}
onChange={(e) => setFormData({ ...formData, date: e.target.value })}
/>
</Grid>
<Button
className={classes.button}
variant="outlined"
color="primary"
fullWidth
onClick={createTransaction}
>
Create
</Button>
</Grid>
);
};
export default Form; ***

why?
you are forget to call the context with in From.js. Because you are created the context hook with same page
Better create the context file seperate js file
context.js
import React,{createContext} from 'react';
export const ExpenseTrackerContext = createContext(null);
Contextr.js
import {ExpenseTrackerContext} from './context.js' // path of context.js
From.js
import React,{useContext} from 'react';
import {ExpenseTrackerContext} from './context.js' // path of context.js
export default function From(props){
const expContext = useContext(ExpenseTrackerContext);
expContext.addTransaction()// you could call like this
...
Updated - React Doc
Accepts a context object (the value returned from React.createContext)
and returns the current context value for that context. The current
context value is determined by the value prop of the nearest
<MyContext.Provider> above the calling component in the tree.
Context passing value only with in tree of children. please check Form.js is execute inside the {children} component of context provider. if you are using parallel or sibling component its does not work
<ExpenseTrackerContext.Provider
value={{
deleteTransaction,
addTransaction,
transactions,
}}
>
{children} // From.js present in this children in any one of the tree otherwise undefined (value only passed inside the provider component tree)
</ExpenseTrackerContext.Provider>

Related

I receive error 400 after changing from Class component to Functional Component

It was working a while ago, the searchBar component was a class component and I tried to change it to a functional component but suddenly I receive error 400. I tried to create a new youtube API but it keeps showing.
is it because of api?
Here is my App.js
import { Grid } from '#material-ui/core'
import React, { useState } from 'react'
import youtube from './api/youtube'
import { SearchBar, VideoDetail, VideoList } from './components'
const App = () => {
const [videos, setVideo] = useState([])
const [selectdvideo, setSelectedVideo] = useState(null)
const onFormSubmit = async (value) => {
const response = await youtube.get('search', {
params: {
part: 'snippet',
maxResults: 5,
key: '',
q: value,
},
})
console.log('hello')
setVideo(response.data.items)
setSelectedVideo(response.data.items[0])
}
return (
<Grid justifyContent="center" container spacing={10}>
<Grid item xs={12}>
<Grid container spacing={10}>
<Grid item xs={12}>
<SearchBar onFormSubmit={onFormSubmit} />
</Grid>
<Grid item xs={8}>
<VideoDetail video={selectdvideo} />
</Grid>
<Grid item xs={4}>
<VideoList videos={videos} onSelectVideo={setSelectedVideo} />
</Grid>
</Grid>
</Grid>
</Grid>
)
}
export default App
This is the searchBar
import { Paper, TextField } from '#material-ui/core'
import React, { useState } from 'react'
const SearchBar = ({ onFormSubmit }) => {
const [searchTerm, setSearchTerm] = useState('')
const handleChange = (event) => setSearchTerm(event.target.value)
const onKeyPress = (event) => {
if (event.key === 'Enter') {
onFormSubmit(searchTerm)
}
}
return (
<Paper elavtion={6} style={{ padding: '25px' }}>
<TextField
fullWidth
label="Search..."
value={searchTerm}
onChange={handleChange}
onKeyPress={onKeyPress}
/>
</Paper>
)
}
export default SearchBar
[enter image description here][1]
I receive this error
https://ibb.co/Vpz9nKG

I use useState hock to store the value but it did not update

I am new to Reactjs
I am trying to build an address form with 3 Select ( country, State, City )
I used React hock
so when the page first load it will fetch countries list to country select after that when user select country it will fetch states list to state select and after that when user select state it will fetch cities list to city select
my issue with state hock I store the value of the user selected in the state but it did not update the value in the state in many locations I keep getting " undefined " like when the page load I get countries list as an array and I get the first country in the list as the default select item in country select but I still get keep getting " undefined " I tried many ways but still getting the same result and bellow is my code
import React,{ useEffect , useState , useCallback } from 'react';
import { InputLabel, Select , MenuItem , Grid , Typography } from '#material-ui/core';
import { useForm, FormProvider } from 'react-hook-form';
import CityHandler from 'countrycitystatejson';
export const TempAddresForm = () =>
{
const methods = useForm();
const [countries, setCountries] = useState([]);
const [countryCode, setCountryCode] = useState('');
const [country, setCountry] = useState('');
const [states, setStates] = useState([]);
const [stateName, setStateName] = useState('');
const [cities, setCities] = useState([]);
const [city, setCity] = useState('');
const fetchCounters = () => {
setCountries(CityHandler.getCountries());
setFirstCountry();
};
const countryChangeHandler = (event) => {
let tempCountryCode = event.target.value;
setCountry(CityHandler.getCountryByShort(tempCountryCode));
setCountryCode(tempCountryCode);
fetchStates(tempCountryCode);
setCities([]);
}
const fetchStates = (countryCode) =>
{
setStates(CityHandler.getStatesByShort(countryCode));
}
const stateChangeHandler = (even) =>
{
let tempState = even.target.value;
setStateName(even.target.value);
fetchCities(tempState);
}
const fetchCities = (stateName) => {
let tempCities = CityHandler.getCities(countryCode, stateName);
setCities(tempCities);
};
const cityChangeHandler = (event) =>
{
let tempCity = event.target.value;
setCity(tempCity);
console.log("Temp City Name : " + tempCity)
console.log("City Name : " + city)
}
const setFirstCountry = useCallback( () =>
{
if(countries)
{
let firstCountry = CityHandler.getCountries()[0];
console.log ("[setFirstCountry] : First Country " + JSON.stringify(firstCountry.name));
setCountry(firstCountry);
console.log ("[setFirstCountry] : Country name " + JSON.stringify(country.name));
}
}, []);
useEffect(() => {
fetchCounters();
//setFirstCountry();
}, []);
return (
<>
<Typography variant="h6" gutterBottom>Shipping Address</Typography>
<FormProvider {...methods}>
<form onSubmit={''}>
<Grid container spacing={3}>
<Grid item xs={12} sm={6}>
<InputLabel>Country</InputLabel>
<Select value={country.name} fullWidth onChange={(event) => {countryChangeHandler(event)}}>
{countries.map((countryLoop) => (
<MenuItem key={countryLoop.shortName} id={countryLoop.shortName} value={countryLoop.shortName}>
{countryLoop.name}
</MenuItem>
))}
</Select>
</Grid>
<Grid item xs={12} sm={6}>
<InputLabel>State</InputLabel>
<Select value={stateName} fullWidth onChange={(event) => {stateChangeHandler(event)}}>
{states.map((state, index) => {
return(
<MenuItem key={index} id={state} value={state}>
{state}
</MenuItem>
);
})}
</Select>
</Grid>
<Grid item xs={12} sm={6}>
<InputLabel>City</InputLabel>
<Select value={city} fullWidth onChange={(event) => {cityChangeHandler(event)}}>
{cities.map((city, index) => {
return(
<MenuItem key={index} id={city} value={city}>
{city}
</MenuItem>
);
})}
</Select>
</Grid>
</Grid>
</form>
</FormProvider>
</>
)
}
export default TempAddresForm;
if anyone could help me with this
*Note: I use this package to get the Country list countrycitystatejson
country is actually always updating but you are logging it in a useCallback hook and did not add country to its dependency array. So it only captures the initial value of country which is an empty string "" and JSON.stringify("".name) is undefined. If you add country to the dependency array of useCallback you will see it updating.
console.log( JSON.stringify("".name) )
You don't need to use useCallback here. Read this article to understand where and when to use useCallback and useMemo
The main problem is that you are mapping your country Select to country.name but your select options have country.shortName as their value - Try changing the Select value to country.shortName.
Also, you have too many state variables that are interdependent to each other. Here moving all your state variables to a single state object will make it a little bit easier to handle.
Ex Like below
{
countries: [...],
states: [...],
cities: [...],
stateName: "..",
...
...
}
countries is always constant & states, cities are just derived values. So your actual state just needs these 3 values countryShortCode, stateName and city.
Here is a snippet with all the above-mentioned changes
import React, { useState } from "react";
import {
InputLabel,
Select,
MenuItem,
Grid,
Typography
} from "#material-ui/core";
import { useForm, FormProvider } from "react-hook-form";
import CityHandler from "countrycitystatejson";
// This countriesList doesn't change so it can just be a constant outside your component
const countriesList = CityHandler.getCountries();
// Your initial state
const initialState = {
countryShortName: countriesList[0].shortName,
stateName: "",
city: ""
};
const TempAddresForm = () => {
const methods = useForm();
const [state, setState] = useState(initialState);
const changeCountry = (e) => {
setState((prevState) => ({
...prevState,
countryShortName: e.target.value,
stateName: "",
city: ""
}));
};
const changeState = (e) => {
setState((prevState) => ({
...prevState,
stateName: e.target.value,
city: ""
}));
};
const changeCity = (e) => {
setState((prevState) => ({
...prevState,
city: e.target.value
}));
};
// Derive both states and cities here ( No need to store it in state :) )
const states = CityHandler.getStatesByShort(state.countryShortName);
const cities = state.stateName
? CityHandler.getCities(state.countryShortName, state.stateName)
: [];
return (
<>
<Typography variant="h6" gutterBottom>
Shipping Address
</Typography>
<FormProvider {...methods}>
<form onSubmit={() => console.log("Submitted")}>
<Grid container spacing={3}>
<Grid item xs={12} sm={6}>
<InputLabel>Country</InputLabel>
<Select
value={state.countryShortName || ""}
fullWidth
onChange={changeCountry}
>
{countriesList.map((countryLoop) => (
<MenuItem
key={countryLoop.shortName}
id={countryLoop.shortName}
value={countryLoop.shortName}
>
{countryLoop.name}
</MenuItem>
))}
</Select>
</Grid>
<Grid item xs={12} sm={6}>
<InputLabel>State</InputLabel>
<Select value={state.stateName} fullWidth onChange={changeState}>
{states.map((state, index) => {
return (
<MenuItem key={index} id={state} value={state}>
{state}
</MenuItem>
);
})}
</Select>
</Grid>
<Grid item xs={12} sm={6}>
<InputLabel>City</InputLabel>
<Select value={state.city || ""} fullWidth onChange={changeCity}>
{cities.map((city, index) => {
return (
<MenuItem key={index} id={city} value={city}>
{city}
</MenuItem>
);
})}
</Select>
</Grid>
</Grid>
</form>
</FormProvider>
</>
);
};
export default TempAddresForm;
Comment if you need to understand anything else

State is empty even have setted up with data

I am trying to fetch the data from the database and storing it in a state but when I console log my state, no data has been stored in the state but when I console the data itself, it returns what I expected to have. This is my code;
import React, { useContext, useEffect, useState } from 'react';
import { Field, Form, Formik, useField } from 'formik';
import * as Yup from 'yup';
import {
Button,
Box,
makeStyles,
Grid,
Typography,
Divider,
FormHelperText,
Select,
MenuItem,
InputLabel,
FormControl,
} from '#material-ui/core';
import {
MuiPickersUtilsProvider,
KeyboardDateTimePicker,
} from '#material-ui/pickers';
import DateFnsUtils from '#date-io/date-fns';
import 'date-fns';
// Yup validation Schema
const validationSchema = Yup.object().shape({
date: Yup.date().required('Please enter valid date').nullable(),
teamOne: Yup.string().required('Please select team'),
teamTwo: Yup.string().required('Please select team'),
});
// This is a custom date field using Formik
const DateTimeField = ({ field, form, ...props }) => {
const currentError = form.errors[field.name];
return (
<MuiPickersUtilsProvider utils={DateFnsUtils}>
<KeyboardDateTimePicker
clearable
disablePast
name={field.name}
value={field.value}
format="MM/dd/yyyy"
helperText={currentError}
error={!!currentError}
onError={(error) => {
if (error !== currentError) {
form.setFieldError(field.name, error);
}
}}
onChange={(date) => form.setFieldValue(field.name, date, true)}
{...props}
/>
</MuiPickersUtilsProvider>
);
};
// Custom <Select> field
const TeamSelection = ({ name, ...props }) => {
const [field, meta] = useField(name);
const errorText = meta.error && meta.touched ? meta.error : '';
return (
<>
<Select
name={field.name}
{...field}
fullWidth
error={!!errorText}
{...props}
>
{props.children}
</Select>
<FormHelperText error>{errorText}</FormHelperText>
</>
);
};
export default function AddMatch() {
const classes = useStyles();
const fetchContext = useContext(FetchContext);
const [team, setTeam] = useState([]);
useEffect(() => {
const getTeam = async () => {
try {
const { data } = await fetchContext.authAxios.get('get-all-teams');
setTeam(data);
} catch (error) {
console.log(error);
}
};
getTeam();
}, [fetchContext]);
console.log(team);
return (
<Formik
initialValues={{ date: new Date(), teamOne: '', teamTwo: '' }}
validationSchema={validationSchema}
onSubmit={(values) => {
if (values.teamOne === values.teamTwo) {
return console.log('Teams must not be the same!');
}
return console.log(values);
}}
>
{() => (
<Form noValidate>
<Grid>
<Typography>
Add Match
</Typography>
</Grid>
<Divider />
<Box>
<Grid>
<Grid>
<Field
name="date"
label="Set date and time"
component={DateTimeField}
/>
</Grid>
<Grid>
<Grid>
<FormControl>
<InputLabel>
Team A
</InputLabel>
<TeamSelection name="teamOne">
<MenuItem value=""> </MenuItem>
{team.map((item) => (
<MenuItem value={item.teamName} key={item._id}>
{item.teamName}
</MenuItem>
))}
</TeamSelection>
</FormControl>
</Grid>
<Grid>
<FormControl>
<InputLabel>
Team B
</InputLabel>
<TeamSelection name="teamTwo">
<MenuItem value=""> </MenuItem>
{team.map((item) => (
<MenuItem value={item.teamName} key={item._id}>
{item.teamName}
</MenuItem>
))}
</TeamSelection>
</FormControl>
</Grid>
</Grid>
<Box>
<Button type="submit">
Submit
</Button>
</Box>
</Grid>
</Box>
</Form>
)}
</Formik>
)}
I'm using Material UI and Formik.
It only logged an empty array "[]" or it makes an error, (.map is not a function). I tried to set the state as an Object but there is still no data being stored with the state.
Check the post request in your res.status(200).json() or res.send() or res.json(). Don't use brackets inside .json() or .send(), in your res or response, for example:
.json({}) // Don't use brackets if you don't want to send your data as an Object
If ever you want it to be object, then call the array which is called data like
useEffect(() => {
const getTeam = async () => {
try {
const { teamsData } = await fetchContext.authAxios.get('get-all-teams');
setTeam(teamsData.data);
} catch (error) {
console.log(error);
}
};
getTeam();
}, [fetchContext]);
destructure the teamsData if you have passed it as an Object on purpose.

Reactjs: Fetch data from API using helper class and functions

I'm beginner for Reactjs and trying to improve myself with a project. As progressing with my project, I now need to setup a structure such that my UI component will connect to some REST API, and use the returned data. This has many examples on the internet and fine.
My question is, if and how I could separate the API connection from the actual UI components. I believe it could be good, as I would have the chance to reuse the API connection functions within various UI components. (It would be ideal to do the common tasks related with API connections within these helper methods.)
For that, I created a PrimaryForm.js file, that is the UI component. And for API calls, I created an APIManager.js file. Ideally, APIManager should not have any jsx, but only functions that return API call results to the PrimaryForm.js.
I am sharing the code I wrote so far, to achieve that.
PrimaryForm.js, that deletages the API call to APIManager.js (see handleTestConnection part below):
import React from 'react';
import withStyles from '#material-ui/styles/withStyles';
import {Link, withRouter } from 'react-router-dom';
import Paper from '#material-ui/core/Paper';
import TextField from '#material-ui/core/TextField';
import Typography from '#material-ui/core/Typography';
import MenuItem from '#material-ui/core/MenuItem';
import FormControl from '#material-ui/core/FormControl';
import InputLabel from '#material-ui/core/InputLabel';
import OutlinedInput from '#material-ui/core/OutlinedInput';
import Select from '#material-ui/core/Select';
import FormHelperText from '#material-ui/core/FormHelperText';
import PrimaryFormValidator from '../../validators/PrimaryFormValidator'
import styles from '../../Styles';
import Grid from '#material-ui/core/Grid';
import Tooltip from '#material-ui/core/Tooltip';
import CancelIcon from '#material-ui/icons/Cancel';
import BackIcon from '#material-ui/icons/ArrowBackIosRounded';
import TestIcon from '#material-ui/icons/Power';
import ForwardIcon from '#material-ui/icons/ArrowForwardIosRounded';
import Button from '#material-ui/core/Button';
import APIManager from '../../managers/APIManager';
function PrimaryForm(props) {
const { classes } = props;
const inputLabel = React.useRef(null);
const [labelWidth, setLabelWidth] = React.useState(0);
React.useEffect(() => {setLabelWidth(inputLabel.current.offsetWidth);}, []);
const [state, setState] = React.useState({
hostname: {
value: "test",
isError: false,
errorText: "",
},
serverIp: {
value: "192.168.16.1",
isError: false,
errorText: "",
},
osVariant: {
value: "Linux",
isError: false,
errorText: "",
},
databaseSid: {
value: "mysql",
isError: false,
errorText: "",
},
listenerPort: {
value: "3306",
isError: false,
errorText: "",
},
isFormValid: true,
isPrimaryDbValid: false,
});
const evaluateFormValid = (prevState) => {
return ((prevState.hostname.value!=="" && !prevState.hostname.isError) &&
(prevState.serverIp.value!=="" && !prevState.serverIp.isError) &&
(prevState.osVariant.value!=="" && !prevState.osVariant.isError) &&
(prevState.databaseSid.value!=="" && !prevState.databaseSid.isError) &&
(prevState.listenerPort.value!=="" && !prevState.listenerPort.isError));
};
const handleChange = event => {
var valResult;
switch (event.target.id) {
case 'hostname':
valResult = PrimaryFormValidator.validateHostname(event.target.value, event.target.labels[0].textContent);
setState({
...state,
hostname:
{
value: event.target.value,
isError: valResult.isError,
errorText: valResult.errorText,
},
});
break;
case 'serverIp':
valResult = PrimaryFormValidator.validateIpAddress(event.target.value, event.target.labels[0].textContent);
setState({
...state,
serverIp:
{
value: event.target.value,
isError: valResult.isError,
errorText: valResult.errorText,
}
});
break;
case 'databaseSid':
valResult = PrimaryFormValidator.validateDatabaseSid(event.target.value, event.target.labels[0].textContent);
setState({
...state,
databaseSid:
{
value: event.target.value,
isError: valResult.isError,
errorText: valResult.errorText,
}
});
break;
case 'listenerPort':
valResult = PrimaryFormValidator.validateListenerPort(event.target.value, event.target.labels[0].textContent);
setState({
...state,
listenerPort:
{
value: event.target.value,
isError: valResult.isError,
errorText: valResult.errorText,
}
});
break;
default:
//setState({...state,});
}
setState(prevState => ({
...prevState,
isFormValid: evaluateFormValid(prevState),
}));
}
const handleTestConnection = event => {
APIManager.testConnection(state.hostname.value, state.serverIp.value, state.osVariant.value, state.databaseSid.value, state.listenerPort.value);
//console.log("Data:" + APIManager.state.testConnectionResult);
}
const handleSelect = osVariant => event => {
var valResult = PrimaryFormValidator.validateOsVariant(event.target.value, inputLabel.current.textContent);
setState(prevState => ({
...prevState,
osVariant:
{
value: event.target.value,
isError: valResult.isError,
errorText: valResult.errorText,
},
}));
setState(prevState => ({
...prevState,
isFormValid: evaluateFormValid(prevState),
}));
}
return (
<React.Fragment>
<div className={classes.bigContainer}>
<Paper className={classes.paper}>
<div>
<div>
<Typography variant="subtitle1" gutterBottom className={classes.subtitle1} color='secondary'>
Primary Database System
</Typography>
<Typography variant="body1" gutterBottom>
Information related with the primary database system. Please note that the primary database has to be up and running.
</Typography>
</div>
<div className={classes.bigContainer}>
<form className={classes.formArea}>
<TextField className={classes.formControl}
id="hostname"
label="FQDN Hostname *"
onChange={handleChange}
value={state.hostname.value}
error={state.hostname.isError}
helperText={state.hostname.errorText}
variant="outlined" autoComplete="off" />
<TextField className={classes.formControl}
id="serverIp"
label="Server Ip Address *"
onChange={handleChange}
value={state.serverIp.value}
error={state.serverIp.isError}
helperText={state.serverIp.errorText}
variant="outlined" autoComplete="off" />
<FormControl variant="outlined" className={classes.formControl}>
<InputLabel id="osVarLabel" htmlFor="osVariant" ref={inputLabel}>OS Variant *</InputLabel>
<Select
id="osVariant"
label="OS Variant *"
value={state.osVariant.value}
error={state.osVariant.isError}
onChange={handleSelect("osVariant")}
input={<OutlinedInput id="outlinedinput" labelWidth={labelWidth}/>}>
<MenuItem value={''}></MenuItem>
<MenuItem value={'Linux'}>Linux</MenuItem>
<MenuItem value={'Windows'}>Windows</MenuItem>
</Select>
<FormHelperText error={state.osVariant.isError} hidden={!state.osVariant.isError}>
{state.osVariant.errorText}
</FormHelperText>
</FormControl>
<TextField className={classes.formControl}
id="databaseSid"
label="Database SID"
onChange={handleChange}
value={state.databaseSid.value}
error={state.databaseSid.isError}
helperText={state.databaseSid.errorText}
variant="outlined" autoComplete="off" />
<TextField className={classes.formControl}
id="listenerPort"
label="Listener Port"
onChange={handleChange}
value={state.listenerPort.value}
error={state.listenerPort.isError}
helperText={state.listenerPort.errorText}
variant="outlined" autoComplete="off" />
{/* <TextField className={classes.formControl}
disabled={true}
id="isFormValid"
label="Is Form Valid Now?"
value={state.isFormValid}
variant="outlined" autoComplete="off" /> */}
</form>
</div>
</div>
</Paper>
<Grid container spacing={2} className={classes.grid}>
<Grid item xs={12}>
<div className={classes.flexBar}>
<Tooltip title="Back to previous step">
<div>
<Button variant="contained"
disabled={true}
className={classes.actionButton}
size='large'>
<BackIcon className={classes.rightIcon}/>Back
</Button>
</div>
</Tooltip>
<Tooltip title="Test Connection">
<div>
<Button variant="contained" className={classes.actionButton}
color="primary"
size='large'
disabled={!state.isFormValid}
onClick={handleTestConnection}>
<TestIcon className={classes.rightIcon}/>Test
</Button>
</div>
</Tooltip>
<Tooltip title="Proceed the next step">
<div>
<Button
variant="contained" className={classes.actionButton}
color="primary"
size='large'
disabled={!state.isPrimaryDbValid}>
<ForwardIcon className={classes.rightIcon} />Next
</Button>
</div>
</Tooltip>
<Tooltip title="Cancel creating new configuration">
<Button variant="contained" color="default" className={classes.actionButton}
component={Link} to={'/configs'} style={{ marginLeft: 'auto' }}>
<CancelIcon className={classes.rightIcon} />Cancel
</Button>
</Tooltip>
</div>
</Grid>
</Grid>
</div>
</React.Fragment>
)
}
export default withRouter(withStyles(styles)(PrimaryForm));
And here is my APIManager.js file:
import React, { Component } from 'react';
export default class APIManager extends Component{
constructor(props) {
super(props);
this.state = {
testConnectionResult: {},
...this.props,
}
this.testConnection = this.testConnection.bind(this);
}
static testConnection(hostname, serverIp, osVariant, databaseSid, listenerPort) {
fetch(`http://localhost:8000/api?objtype=ConnectionDef&hostname=${hostname}&serverIp=${serverIp}&osVariant=${osVariant}&databaseSid=${databaseSid}&listenerPort=${listenerPort}`)
.then(response => response.json())
.then(result => this.setState({testConnectionResult: result}));
//.catch((error) => console.error(error));
console.log("Data:" + this.testConnectionResult);
return this.testConnectionResult;
}
}
Now I could not solve getting below error:
APIManager.js:16 Uncaught (in promise) TypeError: _this2.setState is
not a function
at APIManager.js:16
I guess I'm struggling now to pass the result taken from API call to the external (callee) class / function.
I Googled, also checked other questions on Stackoverflow with this error, but that really didn't help me figure out the issue. I also wanted to ask if I'm making a principal mistake.
Any help would be appreciated. Thanks.
you don't have to create a component just to hold API call logic. in react components are used to declare visual stuff(so they will have jsx).
If you want to extract api call logic out of component, you can put that logic in some function which returns a promise. like so:
function testApi(...args) {
return fetch(/* url parms */)
}
then in your component, on some event say click you can make API call and set response data to component state to change view:
handleTestEvent(...args) {
testApi(...args)
.then(response => response.json())
.then(result => this.setState({testConnectionResult: result}));
.catch((error) => {
console.error(error));
this.setState({testConnectionResult: []});
});
}
You can't access this (an instance context) from a static method. Make it a regular instance method and it should work.

Why react-validation hasErrors issue

I am using react-validation to validate a login form. After submitting the form I want to know has an error or not. I can get the error state inside my custom button object in below way.
const customSubmit = ({ hasErrors, ...props }) => {
return <Button disabled={hasErrors} >Login</Button>
{hasErrors.toString()}/>
};
const SubmitButton = button(customSubmit);
Is there any way to get hasError state when submit a from?
I can share a similar code when I use State and handleChange to get the errors in the button.
First you need a function were you declare the useState.
import React from "react";
import { Box, Button, Collapse, Grid, TextField } from "#material-ui/core";
import { makeStyles } from "#material-ui/core/styles";
function FormVal() {
const [phone, setPhone] = React.useState<string>();
const [errors, setErrors] = React.useState<{ phone: string }>();
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const {
target: { value },
} = event;
setErrors({ phone: "" });
setPhone(value);
let reg = new RegExp(/^\d*$/).test(value);
if (!reg) {
setErrors({ phone: "Only numbers" });
}
};
Now in the return section you need to declare the handleChange. There may be some elements that you don't know such as and that is because I am using Material-ui.
return (
<Box className={classes.root} width="100%" padding="5px">
<Grid container spacing={3}>
<Grid item xs={12}>
<TextField
id="outlined-basic"
autoComplete="off"
value={phone}
label="phone number"
inputProps={{ maxLength: 255 }}
onChange={handleChange}
required
error={Boolean(errors?.phone)}
helperText={errors?.phone}
variant="outlined"
/>
</Grid>
<Collapse in={phone?.length! > 0}>
<div style={{ width: "100%" }}>
<Button variant="contained">Save</Button>
</div>
</Collapse>
</Grid>
</Box>
);
}
export default FormVal;

Categories

Resources