What is the flow of control? - reactjs

I am not understanding the flow of control since I am a newbie. In this code, after the component is rendered, useEffects get called. When the first useEffect is called, it is dispatching an action. So, after the action is dispatched, it should re-render the component because I am fetching the change in state from useSelector. Instead, it is executing the second useEffect. Similar is the case with the third useEffect, after it is triggered, it is changing the formData which is in useState. Instead of re-rendering, it is executing the 4th useEffect. Can anyone please help me understand the flow right from the start to the end?
import React,{useState,useEffect,useRef} from "react";
import AdminLayout from "../../../hoc/adminLayout";
import {useFormik,FieldArray,FormikProvider} from "formik";
import {useDispatch,useSelector} from "react-redux";
import {validation,formValues} from "./validationSchema";
import {getAdminArticle,updateArticle} from "../../../store/actions/articles_actions";
import {clearCurrentArticle} from "../../../store/actions/index";
import Loader from "../../../utils/loader";
import {
TextField,
Button,
Divider,
Chip,
Paper,
InputBase,
IconButton,
Select,
MenuItem,
FormControl,
FormHelperText
} from '#material-ui/core';
import AddIcon from '#material-ui/icons/Add';
import WYSIWYG from "../../../utils/forms/wysiwyg";
const EditArticle=(props)=>{
const dispatch=useDispatch();
const notifications=useSelector((state)=>{
return state.notifications;
})
const articles=useSelector((state)=>{
return state.articles;
})
const [isLoading, setIsLoading]=useState(true);
const [editorBlur,setEditorBlur]=useState(false);
const [formData,setFormData]=useState(formValues);
const actorsValue=useRef("");
/////edit/////
const [editContent,setEditContent]=useState(null);
////edit////
const formik=useFormik({
enableReinitialize:true,
initialValues:formData,
validationSchema:validation,
onSubmit:(values,{resetForm})=>{
//console.log(values);
setIsLoading(true);
dispatch(updateArticle(values,props.match.params.id));
}
});
const handleEditorState=(state)=>{
formik.setFieldValue("content",state,true);
}
const handleEditorBlur=(blur)=>{
setEditorBlur(true);
}
const errorHelper=(formik,value)=>{
return {
error:formik.errors[value] && formik.touched[value]? true:false,
helperText:formik.errors[value] && formik.touched[value]?formik.errors[value]:null
}
}
///////edit/////////
useEffect(()=>{
console.log("first");
dispatch(getAdminArticle(props.match.params.id));
},[dispatch,props.match.params])
/////edit///////
useEffect(()=>{
console.log("second");
// if(notifications && notifications.success){
// props.history.push("/dashboard/articles");
// }
// if(notifications && notifications.error){
setIsLoading(false);
// }
},[notifications,props.history])
useEffect(()=>{
console.log("third");
if(articles && articles.current){
setFormData(articles.current);
setEditContent(articles.current.content);
}
},[articles])
useEffect(()=>{
console.log("unmounted");
return ()=>{
dispatch(clearCurrentArticle());
}
},[dispatch])
return <AdminLayout section="Add Article">
{console.log("rendered")}
{isLoading?<Loader />:<form className="mt-3 article_form" onSubmit={formik.handleSubmit}>
<div className="form-group">
<TextField
style={{width:"100%"}}
name="title"
label="Enter a title"
variant="outlined"
{...formik.getFieldProps("title")}
{...errorHelper(formik,"title")}
/>
</div>
<div className="form-group">
<WYSIWYG setEditorState={(state)=>{
return handleEditorState(state)
}} setEditorBlur={(blur)=>{
return handleEditorBlur(blur)
}}
editContent={editContent}
/>
{formik.errors.content && editorBlur?
<FormHelperText error={true}>
{formik.errors.content}
</FormHelperText> :null}
<TextField
type="hidden"
name="content"
{...formik.getFieldProps("content")}
/>
</div>
<div className="form-group">
<TextField
style={{width:"100%"}}
name="excerpt"
label="Enter an excerpt"
variant="outlined"
{...formik.getFieldProps("excerpt")}
{...errorHelper(formik,"excerpt")}
multiline
rows={4}
/>
</div>
<Divider className="mt-3 mb-3" />
<h5>Movie Data and Score</h5>
<div className="form-group">
<TextField
style={{width:"100%"}}
name="score"
label="Enter an score"
variant="outlined"
{...formik.getFieldProps("score")}
{...errorHelper(formik,"score")}
/>
</div>
<FormikProvider value={formik}>
<h5>Add the Actors</h5>
<FieldArray name="actors"
render={
arrayhelpers=>(
<div>
<Paper className="actors_form">
<InputBase
className="input"
placeholder="Add actor name here"
inputRef={actorsValue}
/>
<IconButton onClick={()=>{
arrayhelpers.push(actorsValue.current.value);
actorsValue.current.value="";
}}>
<AddIcon />
</IconButton>
</Paper>
{formik.errors.actors && formik.touched.actors?
<FormHelperText error={true}>
{formik.errors.actors}
</FormHelperText> :null}
<div className="chip_container">
{formik.values.actors.map((actor,index)=>{
return <div key={actor}>
<Chip label={`${actor}`} color="primary" onDelete={()=>{
return arrayhelpers.remove(index);
}}>
</Chip>
</div>
})}
</div>
</div>
)
}
/>
</FormikProvider>
<div className="form-group">
<TextField
style={{width:"100%"}}
name="score"
label="Enter the Director"
variant="outlined"
{...formik.getFieldProps("director")}
{...errorHelper(formik,"director")}
/>
</div>
<FormControl variant="outlined" >
<h5>Select a Status</h5>
<Select
name="status"
{...formik.getFieldProps("status")}
error={formik.errors.status && formik.touched.status? true:false}
>
<MenuItem value=""><em>None</em></MenuItem>
<MenuItem value="draft">Draft</MenuItem>
<MenuItem value="public">Public</MenuItem>
</Select>
{formik.errors.status && formik.touched.status?
<FormHelperText error={true}>
{formik.errors.status}
</FormHelperText> :null}
</FormControl>
<Divider className="mt-3 mb-3" />
<Button variant="contained" color="primary" type="submit" >
Edit Article
</Button>
</form>
}
</AdminLayout>
}
export default EditArticle;
[enter image description here][1]

Related

I want the answer to a question to appear on the screen for confirmation

We are using Material-UI in React to create a web form.
In components / Content.js, case 3: I want to create a confirmation screen that displays the answer to the question below.
I've done a lot of research, but I'm stuck in a situation where I don't know how to implement it.
Can anyone give me some advice?
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
reportWebVitals();
App.js
import "./App.css";
import { Grid } from "#mui/material";
import Header from "./components/Header";
import Content from "./components/Content";
function App() {
return (
<Grid container direction="column">
<Header />
<div style={{ padding: 30 }}>
<Content />
</div>
</Grid>
);
}
export default App;
src / components / contents.js
import React from "react";
import { Grid } from "#mui/material";
import Stepper from "#mui/material/Stepper";
import Step from "#mui/material/Step";
import StepLabel from "#mui/material/StepLabel";
import Button from "#mui/material/Button";
import Typography from "#mui/material/Typography";
import Radio from "#mui/material/Radio";
import RadioGroup from "#mui/material/RadioGroup";
import FormControlLabel from "#mui/material/FormControlLabel";
import FormControl from "#mui/material/FormControl";
import FormLabel from "#mui/material/FormLabel";
import Tooltip from "#mui/material/Tooltip";
import TextField from "#mui/material/TextField";
import InputLabel from "#mui/material/InputLabel";
import Select from "#mui/material/Select";
function getSteps() {
return ["お客様の情報を入力してください", "以下にお答えください", "ご相談ください", "以下の内容をご確認ください"];
}
function getStepContent(stepIndex) {
switch (stepIndex) {
case 0:
return (
<>
{/* <DatePicker views={["year"]} label="Year only" value={selectedDate} onChange={handleDateChange} /> */}
<div>
<FormControl component="fieldset">
<FormLabel component="legend">- 性別 -</FormLabel>
<RadioGroup row aria-label="gender" name="row-radio-buttons-group">
<FormControlLabel value="male" control={<Radio />} label="男性" />
<FormControlLabel value="female" control={<Radio />} label="女性" />
</RadioGroup>
</FormControl>
</div>
<div>
<FormLabel component="legend">- 生年月日 -</FormLabel>
<FormControl sx={{ m: 1, minWidth: 120 }}>
<InputLabel htmlFor="grouped-native-select">year</InputLabel>
<Select native defaultValue="" id="grouped-native-select" label="Grouping">
<option aria-label="None" value="" />
<optgroup label="year">
{Array.from(Array(2020), (_, num) => (
<option key={num} value={num + 1}>
{num + 1990}
</option>
))}
</optgroup>
</Select>
</FormControl>
<FormControl sx={{ m: 1, minWidth: 120 }}>
<InputLabel htmlFor="grouped-native-select">month</InputLabel>
<Select native defaultValue="" id="grouped-native-select" label="Grouping">
<option aria-label="None" value="" />
<optgroup label="month">
{Array.from(Array(12), (_, num) => (
<option key={num} value={num + 1}>
{num + 1}
</option>
))}
</optgroup>
</Select>
</FormControl>
<FormControl sx={{ m: 1, minWidth: 120 }}>
<InputLabel htmlFor="grouped-native-select">day</InputLabel>
<Select native defaultValue="" id="grouped-native-select" label="Grouping">
<option aria-label="None" value="" />
<optgroup label="day">
{Array.from(Array(31), (_, num) => (
<option key={num} value={num + 1}>
{num + 1}
</option>
))}
</optgroup>
</Select>
</FormControl>
</div>
</>
);
case 1:
return (
<div>
<FormControl component="fieldset">
<FormLabel component="legend">現在、生命保険に加入されていますか?</FormLabel>
<RadioGroup row aria-label="gender" name="row-radio-buttons-group">
<FormControlLabel value="yes" control={<Radio />} label="はい" />
<FormControlLabel value="no" control={<Radio />} label="いいえ" />
</RadioGroup>
<FormLabel component="legend">
現在、入院中ですか。また、3ヶ月以内に医師の診察・検査の結果、入院・手術をすすめられたことがありますか?
</FormLabel>
<RadioGroup row aria-label="gender" name="row-radio-buttons-group">
<FormControlLabel value="yes" control={<Radio />} label="はい" />
<FormControlLabel value="no" control={<Radio />} label="いいえ" />
</RadioGroup>
<FormLabel component="legend">
過去、5年以内に病気やケガで手術を受けたことまたは継続して7日以上の入院をしたことはありますか?
</FormLabel>
<RadioGroup row aria-label="gender" name="row-radio-buttons-group">
<FormControlLabel value="yes" control={<Radio />} label="はい" />
<FormControlLabel value="no" control={<Radio />} label="いいえ" />
</RadioGroup>
</FormControl>
</div>
);
case 2:
return (
<Grid container>
<Grid sm={2} />
<Grid lg={8} sm={8} spacing={10}>
<Tooltip title="ご相談内容を記入することができます" placement="top-start" arrow>
<TextField
label="ご相談内容"
fullWidth
margin="normal"
rows={4}
multiline
variant="outlined"
placeholder="その他ご要望等あれば、ご記入ください"
/>
</Tooltip>
</Grid>
</Grid>
);
case 3:
return (
<div>
<FormControl component="fieldset">
<FormLabel component="legend">- 性別 -</FormLabel>
<FormLabel component="legend">- 生年月日 -</FormLabel>
<FormLabel component="legend">現在、生命保険に加入されていますか?</FormLabel>
<FormLabel component="legend">
現在、入院中ですか。また、3ヶ月以内に医師の診察・検査の結果、入院・手術をすすめられたことがありますか?
</FormLabel>
<FormLabel component="legend">
過去、5年以内に病気やケガで手術を受けたことまたは継続して7日以上の入院をしたことはありますか?
</FormLabel>
<FormLabel component="legend">ご相談内容</FormLabel>
</FormControl>
</div>
);
default:
return "Unknown stepIndex";
}
}
function Content() {
const [activeStep, setActiveStep] = React.useState(0);
const steps = getSteps();
const handleNext = () => {
setActiveStep((prevActiveStep) => prevActiveStep + 1);
};
const handleBack = () => {
setActiveStep((prevActiveStep) => prevActiveStep - 1);
};
const handleReset = () => {
setActiveStep(0);
};
return (
<Grid container>
<Grid sm={2} />
<Grid lg={8} sm={8} spacing={10}>
<Stepper activeStep={activeStep} alternativeLabel>
{steps.map((label) => (
<Step key={label}>
<StepLabel>{label}</StepLabel>
</Step>
))}
</Stepper>
{activeStep === steps.length ? (
<div>
<Typography>全ステップの表示を完了</Typography>
<Button onClick={handleReset}>リセット</Button>
</div>
) : (
<div>
<Typography>{getStepContent(activeStep)}</Typography>
<Button disabled={activeStep === 0} onClick={handleBack}>
戻る
</Button>
<Button variant="contained" color="primary" onClick={handleNext}>
{activeStep === steps.length - 1 ? "送信" : "次へ"}
</Button>
</div>
)}
</Grid>
</Grid>
);
}
export default Content;

Dynamically change value in Formik when a state changes

I need to change the value in my form fields every time a state (called selectedProduct, its input field is not included in Formik tag) changes.
I tried:
putting the value I want in the initialValues (does not work obviously because at the first render I haven't choosen my selectedProduct yet)
putting the value I want in the "value" props in every field in formik.
It almost work: Datepicker gets the right value, select box input does not get any value(idk why), text field take the right value but this is covered by the label. And that's because none of the fields get validated.
This is what I've done, with the two points above applied
import React, { useState } from 'react';
import * as Yup from 'yup';
import {
Formik, Form, ErrorMessage, Field,
} from 'formik';
import {
Button, TextField,
MenuItem,
} from '#material-ui/core';
import DateFnsUtils from '#date-io/date-fns';
import {
MuiPickersUtilsProvider,
KeyboardDatePicker,
} from '#material-ui/pickers';
const validationSchema = Yup.object().shape({
startValidityDate: Yup.date().required(),
discount: Yup.string().required(),
days: Yup.string().required(),
});
const MyComponent = ({filteredProduct, daysList}) => {
const [selectedProduct, setSelectedProduct] = useState('');
const onChangeProduct = (product) => {
setSelectedProduct(product.target.value);
};
const handleRunButton = (newExecution) => {
console.log(newExecution);
};
return (
<div>
<div className={classes.productComboWrapper}>
<div id="selectBoxNotIncludedInFormik">
<TextField
margin="normal"
style={{}}
variant="outlined"
name="productId"
id="productId"
fullWidth
select
label="Select product"
value={selectedProduct?.id}
onChange={(product) => onChangeProduct(product)}
>
<MenuItem key="" value="">
{StringsConst.noneSelected}
</MenuItem>
{filteredProduct?.map((el) => (
<MenuItem key={el} value={el}>
{el.isin}
</MenuItem>
))}
</TextField>
</div>
</div>
<Formik
initialValues={{
startValidityDate: selectedProduct?.startValidityDate,
days: selectedProduct?.coupon?.days,
discount: selectedProduct?.discount,
}}
validationSchema={validationSchema}
onSubmit={(values) => {
const newExecution = {
startValidityDate: values.startValidityDate,
days: values.days,
discount: values.discount,
};
handleRunButton(newExecution);
}}
>
{({
errors, dirty, setFieldValue, values,
}) => (
<Form>
<div className={classes.datePicker}>
<MuiPickersUtilsProvider utils={DateFnsUtils}>
<KeyboardDatePicker
disableToolbar
label="Start Validity Date"
inputVariant="outlined"
variant="inline"
autoOk
fullWidth
disabled
format="dd/MM/yyyy"
value={selectedProduct?.startValidityDate}
onChange={(dt) => setFieldValue('startValidityDate', dt)}
KeyboardButtonProps={{
'aria-label': 'change date',
}}
/>
</MuiPickersUtilsProvider>
</div>
<div className={classes.fieldWrapper}>
<Field
className={classes.field}
name="discount"
as={TextField}
variant="outlined"
margin="normal"
fullWidth
id="discount"
autoComplete="discount"
placeholder="Discount"
disabled
value={selectedProduct?.discount}
/>
</div>
<div className={classes.textFieldWrapper}>
<TextField
margin="normal"
style={{}}
variant="outlined"
name="days"
id="days"
fullWidth
select
label="Days"
disabled
value={selectedProduct?.coupon?.days}
onChange={(val) => setFieldValue('days', val.target.value)}
>
<MenuItem key="" value="">
{StringsConst.noneSelected}
</MenuItem>
{daysList.map((el) => (
<MenuItem key={el} value={el}>
{el}
</MenuItem>
))}
</TextField>
</div>
<div className={classes.buttonContainer}>
<Button
type="submit"
fullWidth
variant="contained"
color="primary"
className={classes.submit}
>
{StringsConst.Run}
</Button>
</div>
</Form>
)}
</Formik>
</div>
)
}
So, the three input fields in the form are disabled, but I need them to fill when I choose a value in the first select box outside of the form.
Can you suggest me another approach?
You can connect input or button to the form outside the form.
like this code:
<form id="myForm">
<button> click me </button>
</form>
<input type="text" form="myForm"/>
ref: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#htmlattrdefform

React - Material-UI - How to use Select with multiple values inside react-hook-form

I am trying to use UI-Material Select with multiple options inside react-hook-form without success.
I had this working before trying to do it with multiple options
<form onSubmit={handleSubmit(onSubmit)}>
<Row className="mb-2">
<Col sm={6}>
<FormControl className="select-language">
<InputLabel> {t('Languages')}</InputLabel>
<Controller
as={
<Select>
{Config.languages.map(m => <MenuItem key={m.code} value={m.text}> {t(m.text)} </MenuItem>)}
</Select>
}
defaultValue={user.language}
name="language"
control={control}
>
</Controller>
</FormControl>
</Col>
</Row>
</form>
I tried to add multiple to the Select element which lead me to another error.
I tried also to keep only the Select element without the Controller wrapper, but then I can't get the language value in onSubmit
Very simple codeSandBox that shows that I can't get value from Select when submitting the form: https://codesandbox.io/s/react-hook-form-example-s7h5p?file=/src/index.js
I would appreciate any help
Thanks
If anyone looking for a easy solution, this might come in handy. Multiple select options become very easy now with Select Component. If you look at the Select component, you just have to set the default value to an array and pass the "multiple" prop.
import {
Button,
FormControl,
InputLabel,
MenuItem,
Select
} from "#mui/material";
import { Controller, useForm } from "react-hook-form";
const FCWidth = {
width: "20rem"
};
export default function App() {
const { control, handleSubmit } = useForm();
const formSubmitHandler = (formData) => {
console.log(formData);
};
const ages = ["10", "20", "30"];
return (
<div className="App">
<form onSubmit={handleSubmit(formSubmitHandler)}>
<Controller
name="age"
control={control}
type="text"
defaultValue={[]}
render={({ field }) => (
<FormControl sx={FCWidth}>
<InputLabel id="age">Age</InputLabel>
<Select
{...field}
labelId="age"
label="age"
multiple
defaultValue={[]}
>
{ages.map((age) => (
<MenuItem value={age} key={age}>
{age}
</MenuItem>
))}
</Select>
</FormControl>
)}
/>
<FormControl sx={FCWidth}>
<Button
type="submit"
variant="contained"
fullWidth
sx={{ marginTop: ".75rem", fontWeight: "bold" }}
>
Submit
</Button>
</FormControl>
</form>
</div>
);
}
Here is the code sandbox link https://codesandbox.io/s/select-multiple-option-with-mui-and-react-hook-form-2kv2o
I know that this old but someone may need it later, maybe this one would work for you,
just check the render Controller props
import React from "react";
import {
TextField,
ListItemText,
Checkbox,
MenuItem,
makeStyles
} from "#material-ui/core";
import { useForm, Controller } from "react-hook-form";
const useStyles = makeStyles({
root: {
width: "200px"
},
center: {
textAlign: "center"
}
});
export default function SelectTextField() {
const classes = useStyles();
const { handleSubmit, control } = useForm();
const nums = [1, 2, 3, 4];
const onSubmit = (e) => {
console.log(e);
};
return (
<form className={classes.center} onSubmit={handleSubmit(onSubmit)}>
<Controller
control={control}
name="selectedNumbers"
defaultValue={[]}
render={({ onChange, value }) => {
console.log(value);
return (
<TextField
classes={{ root: classes.root }}
select
id="Numbers"
variant="outlined"
label="Numbers"
SelectProps={{
multiple: true,
value: value,
renderValue: (selected) => selected.join(", "),
onChange: onChange
}}
>
{nums.map((n) => (
<MenuItem key={n} value={n}>
<Checkbox checked={value.includes(n)} />
<ListItemText primary={n} />
</MenuItem>
))}
</TextField>
);
}}
/>
<div>
<button type="submit">Submit</button>
</div>
</form>
);
}
also, you can and play with it here
https://codesandbox.io/s/multi-select-input-u0cr3?file=/demo.js
also can check this on the docs
https://react-hook-form.com/get-started#ReactNative
First of all, i think your version is on v3, so you may want to upgrade:
https://codesandbox.io/s/react-hook-form-example-5lrij?file=/src/index.js
import React from "react";
import ReactDOM from "react-dom";
import { useForm, Controller } from "react-hook-form";
import { Select, MenuItem } from "#material-ui/core";
import "./styles.css";
const languages = [
{
code: "en-US",
text: "English"
},
{
code: "zu",
text: "Another Language"
}
];
export default function App() {
const { register, handleSubmit, control } = useForm();
const onSubmit = data => console.log(data);
return (
<div className="container">
<div className="col-sm-12">
<h3>Client Profile</h3>
</div>
<div className="col-sm-12">
<form onSubmit={handleSubmit(onSubmit)}>
<div className="form-group">
<input
className="form-control"
type="text"
placeholder="Name"
name="Name"
ref={register}
/>
</div>
<div className="form-group">
<Controller
name="Language"
control={control}
as={
<Select>
{languages.map(m => (
<MenuItem key={m.code} value={m.text}>
{" "}
{m.text}{" "}
</MenuItem>
))}
</Select>
}
defaultValue={languages[0].text}
/>
</div>
<div className="form-group">
<input className="btn btn-primary" type="submit" />
</div>
</form>
</div>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
here is the fixed version by using Controller

How to use custom radio component with react-final-form?

I am trying to use a custom Radio component with React-final-form but it is not acting as a radio button but as a checkbox, ie, all the buttons are open for selection.
The 3rd party Radio button has the following schema:
checked boolean
Whether or not radio is checked
onChange () => void
Called when the user attempts to change the checked state
name string
The input name, used to reference the element in JavaScript
I created a custom Component for using the Radio Component:
const CustomRadio = (props: any) => (
<Radio
{...props.input}
{...props.rest}
name={props.name}
onChange={() => props.input.onChange()}
/>
)
and I am using it as follows:
<Field name="food"
component={CustomRadio}
value="1"
/>
<Field name="food"
component={CustomRadio}
value="2"
/>
Being very new to RFF and new to React, I may be doing something very wrong, hence any help will be appreciated.
Basically, I want to use RFF with my 3rd party components. Though I have been successful to use my Input component with RFF as expected, Radio Button is the one creating problems.
Here is the correct implementation for Radio with react-final-form:-
https://codesandbox.io/s/vibrant-easley-5n1ek?file=/index.js
/* eslint-disable jsx-a11y/accessible-emoji */
import React from "react";
import { render } from "react-dom";
import Styles from "./Styles";
import { Form, Field } from "react-final-form";
import RadioGroup from "#material-ui/core/RadioGroup";
import FormControlLabel from "#material-ui/core/FormControlLabel";
import FormControl from "#material-ui/core/FormControl";
import Radio from "#material-ui/core/Radio";
import FormLabel from "#material-ui/core/FormLabel";
const RadioWrapper = (props) => {
const {
input: { checked, value, name, onChange, ...restInput },
} = props;
return (
<Radio
name={name}
inputProps={restInput}
onChange={onChange}
checked={checked}
value={value}
/>
);
};
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
const onSubmit = async (values) => {
await sleep(300);
window.alert(JSON.stringify(values, 0, 2));
};
const App = () => {
return (
<Styles>
<h1>React Final Form - Simple Example</h1>
<a
href="https://final-form.org/react"
target="_blank"
rel="noopener noreferrer"
>
Read Docs
</a>
<Form
onSubmit={onSubmit}
initialValues={{
employed: false,
all_sub_tenants: "true"
}}
render={({ handleSubmit, form, submitting, pristine, values }) => (
<form onSubmit={handleSubmit}>
<FormControl component="fieldset">
<FormLabel component="legend">
Select Tenants
</FormLabel>
<RadioGroup aria-label="allSubTenants" name="allSubTenants">
<FormControlLabel
value="true"
control={
<Field
name="all_sub_tenants"
component={RadioWrapper}
type="radio"
value={"true"}
/>
}
label="All Sub-Tenants"
/>
<FormControlLabel
value="false"
control={
<Field
name="all_sub_tenants"
component={RadioWrapper}
type="radio"
value={"false"}
/>
}
label="Select Sub-Tenants"
/>
</RadioGroup>
</FormControl>
<div>
<label>Notes</label>
<Field name="notes" component="textarea" placeholder="Notes" />
</div>
<div className="buttons">
<button type="submit" disabled={submitting || pristine}>
Submit
</button>
<button
type="button"
onClick={form.reset}
disabled={submitting || pristine}
>
Reset
</button>
</div>
<pre>{JSON.stringify(values, 0, 2)}</pre>
</form>
)}
/>
</Styles>
);
};
render(<App />, document.getElementById("root"));

Unable to Grab value from Textfield in React?

Code is given below. where there is a form and I want to get value from textfield of FullName and Email but I am getting error of undefined property for email. I want to access the Text field value. How can I do that i this is not propare way. Note that I am not fluent in React.
Error I am Getting in my COde is Given below.
index.js?aa0c:21 Uncaught TypeError: Cannot read property 'email' of undefined
at Object.onClick (eval at ./app/containers/LoginPage/index.js (http://localhost:3001/0.chunk.js:7:1), <anonymous>:104:27)
at Object.proxiedMethod [as onClick] (eval at ./node_modules/react-proxy/modules/createPrototypeProxy.js (http://localhost:3001/main.js:2282:1), <anonymous>:44:30)
at EnhancedButton._this.handleClick (webpack:///./~/material-ui/internal/EnhancedButton.js?:144:21)
at Object.ReactErrorUtils.invokeGuardedCallback (webpack:///./~/react-dom/lib/ReactErrorUtils.js?:69:16)
at executeDispatch (webpack:///./~/react-dom/lib/EventPluginUtils.js?:85:21)
at Object.executeDispatchesInOrder (webpack:///./~/react-dom/lib/EventPluginUtils.js?:108:5)
at executeDispatchesAndRelease (webpack:///./~/react-dom/lib/EventPluginHub.js?:43:22)
at executeDispatchesAndReleaseTopLevel (webpack:///./~/react-dom/lib/EventPluginHub.js?:54:10)
at Array.forEach (native)
at forEachAccumulated (webpack:///./~/react-dom/lib/forEachAccumulated.js?:24:9)
at Object.processEventQueue (webpack:///./~/react-dom/lib/EventPluginHub.js?:257:7)
this is my index.js file.
import React, { Component } from 'react';
import { Field, reduxForm } from 'redux-form';
import TextField from 'material-ui/TextField';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
import DatePicker from 'material-ui/DatePicker';
import { RadioButton, RadioButtonGroup } from 'material-ui/RadioButton';
import SelectField from 'material-ui/SelectField';
import MenuItem from 'material-ui/MenuItem';
import { GridList, GridTile } from 'material-ui/GridList';
import Checkbox from 'material-ui/Checkbox';
import RaisedButton from 'material-ui/RaisedButton';
export default class Login extends Component {
state = {
value: null,
};
onClick() {
const text = this.refs.email.getValue();
console.log("when clicking, the form data is:", text);
console.log(this.refs.email.getValue());
}
handleChange = (event, index, value) => this.setState({ value });
render() {
return (
<div className="md-card">
<div className="md-card-content large-padding">
<form id="form_validation" className="uk-form-stacked" >
<div className="uk-grid" data-uk-grid-margin>
<div className="uk-width-medium-1-2">
<div className="parsley-row">
<TextField
ref={(input) => { this.fullname = input; }}
floatingLabelText="Full Name"
fullWidth={true}
/>
</div>
</div>
<div className="uk-width-medium-1-2">
<div className="parsley-row">
<TextField
hintText=""
ref='email'
floatingLabelText="Email"
fullWidth={true}
/>
</div>
</div>
</div>
<div className="uk-grid" data-uk-grid-margin>
<div className="uk-width-medium-1-2">
<div className="parsley-row">
<DatePicker
hintText="Birthdate"
container="inline"
mode="landscape"
fullWidth={true}
/>
</div>
</div>
<div className="uk-width-medium-1-2">
<div className="parsley-row">
<label className="uk-form-label">Gender:</label>
<RadioButtonGroup name="shipSpeed" defaultSelected="not_light" >
<RadioButton
value="Male"
label="Male"
/>
<RadioButton
value="Female"
label="Female"
/>
</RadioButtonGroup>
</div>
</div>
</div>
<div className="uk-grid">
<div className="uk-width-medium-1-2">
<div className="parsley-row">
<label className="uk-form-label">Hobbies:</label>
<span className="icheck-inline">
<Checkbox
label="Skiing"
/>
</span>
<span className="icheck-inline">
<Checkbox
label="Running"
/>
</span>
<span className="icheck-inline">
<Checkbox
label="Reading"
/>
</span>
<span className="icheck-inline">
<Checkbox
label="Swimming"
/>
</span>
</div>
</div>
<div className="uk-width-medium-1-2">
<SelectField
floatingLabelText="Press?"
value={this.state.value}
onChange={this.handleChange}
>
<MenuItem value={null} primaryText="" />
<MenuItem value={false} primaryText="Internet" />
<MenuItem value={true} primaryText="Words of Mouth" />
</SelectField>
</div>
</div>
<div>
<TextField
hintText=""
floatingLabelText="Message"
multiLine={true}
rows={2}
rowsMax={4}
fullWidth={true}
/>
</div>
<RaisedButton label="Primary" primary={true} onClick={this.onClick} />
</form >
</div>
</div>
);
}
}
Getting value of components (ex. Inputs) using ref is not right way in Reactive Functional Programming. (Read this: https://facebook.github.io/react/docs/forms.html)
Try to listen on change event of each Input and keep they changes into state, so you can provide a value to them and control them. This will able you to have values, clean them up or change them from somewhere else.
Here is your code with controlled inputs of fullname and email.
Also you can check this out in material-ui docs (under Controlled Example section of each component).
import React, { Component } from 'react';
import { Field, reduxForm } from 'redux-form';
import TextField from 'material-ui/TextField';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
import DatePicker from 'material-ui/DatePicker';
import { RadioButton, RadioButtonGroup } from 'material-ui/RadioButton';
import SelectField from 'material-ui/SelectField';
import MenuItem from 'material-ui/MenuItem';
import { GridList, GridTile } from 'material-ui/GridList';
import Checkbox from 'material-ui/Checkbox';
import RaisedButton from 'material-ui/RaisedButton';
export default class Login extends Component {
state = {
value: null,
fullname: ""
email: ""
};
onClick() {
console.log(this.state.fullname);
console.log(this.state.email);
}
handleChange = (event, index, value) => this.setState({ value });
render() {
return (
<div className="md-card">
<div className="md-card-content large-padding">
<form id="form_validation" className="uk-form-stacked" >
<div className="uk-grid" data-uk-grid-margin>
<div className="uk-width-medium-1-2">
<div className="parsley-row">
<TextField
ref={(input) => { this.fullname = input; }}
floatingLabelText="Full Name"
fullWidth={true}
value={this.state.fullname}
onChange={(event, value) => { this.setState({ fullname: value }); }}
/>
</div>
</div>
<div className="uk-width-medium-1-2">
<div className="parsley-row">
<TextField
hintText=""
ref='email'
floatingLabelText="Email"
fullWidth={true}
value={this.state.email}
onChange={(event, value) => { this.setState({ email: value }); }}
/>
</div>
</div>
</div>
<div className="uk-grid" data-uk-grid-margin>
<div className="uk-width-medium-1-2">
<div className="parsley-row">
<DatePicker
hintText="Birthdate"
container="inline"
mode="landscape"
fullWidth={true}
/>
</div>
</div>
<div className="uk-width-medium-1-2">
<div className="parsley-row">
<label className="uk-form-label">Gender:</label>
<RadioButtonGroup name="shipSpeed" defaultSelected="not_light" >
<RadioButton
value="Male"
label="Male"
/>
<RadioButton
value="Female"
label="Female"
/>
</RadioButtonGroup>
</div>
</div>
</div>
<div className="uk-grid">
<div className="uk-width-medium-1-2">
<div className="parsley-row">
<label className="uk-form-label">Hobbies:</label>
<span className="icheck-inline">
<Checkbox
label="Skiing"
/>
</span>
<span className="icheck-inline">
<Checkbox
label="Running"
/>
</span>
<span className="icheck-inline">
<Checkbox
label="Reading"
/>
</span>
<span className="icheck-inline">
<Checkbox
label="Swimming"
/>
</span>
</div>
</div>
<div className="uk-width-medium-1-2">
<SelectField
floatingLabelText="Press?"
value={this.state.value}
onChange={this.handleChange}
>
<MenuItem value={null} primaryText="" />
<MenuItem value={false} primaryText="Internet" />
<MenuItem value={true} primaryText="Words of Mouth" />
</SelectField>
</div>
</div>
<div>
<TextField
hintText=""
floatingLabelText="Message"
multiLine={true}
rows={2}
rowsMax={4}
fullWidth={true}
/>
</div>
<RaisedButton label="Primary" primary={true} onClick={this.onClick} />
</form >
</div>
</div>
);
}
}

Resources