I want to pass my input values from form to handleSubmit () currently I am passing e.target.value and getting an error cannot property 'value' of undefined.
following is the form code block from where I want to get the values
<Input
label="Write a message..."
name="message"
type="text"
/>
and the following is the code block from where I am trying to access the value under
handleSubmit = (e) => {
this.props.sendNewMessage(e.target.value);
}
Full code for reference :
import React from 'react';
import SubMenu from './SubMenu';
import MessageForm from './form/MessageForm';
import { sendNewMessage } from '../../actions/messages.actions'
import {connect} from 'react-redux';
class Messages extends React.PureComponent {
handleSubmit = (e) => {
this.props.sendNewMessage(e.target.value);
}
render() {
return (
<section className="page-notifications">
<SubMenu/>
<MessageForm onSubmit={this.handleSubmit}/>
</section>
)
}
}
const mapDispatchToProps = dispatch => {
return {
sendNewMessage: (msg) => dispatch(sendNewMessage(msg)),
}
}
export default connect(null,mapDispatchToProps)(Messages)
This isn't how you should handle form submissions. Your messageForm should update your state using an onChange handler. Then handleSubmit should preventDefault() and dispatch your sendNewMessage action using the value(s) from state that have already been set.
The React docs are very helpful on this.
You need to bind your method for getting value from child component
constructer(props){
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
}
Now you shouldn't get undefined error
So #Will suggested me to add values to my handleSubmit(), it solved my problem thank you all.
following is code snippet where I made changes :
handleSubmit = (value) => {
this.props.sendNewMessage(value);
console.log(value)
}
Related
I am using a basic example of the react-hook-form library and even after looking up the documentary, I do not know how to pass the data from the form to another component. Here is my form component:
import { useForm, SubmitHandler } from "react-hook-form";
type FormInputs = {
minimalFrequency: number;
maximialFrequency: number;
};
// const onSubmit: SubmitHandler<FormInputs> = data => console.log(data);
export default function BasicUsage() {
const { register, formState: { errors }, handleSubmit, getValues } = useForm<FormInputs>({
defaultValues: {
min: 250,
max: 8000,
}
});
const onSubmit = (data: any) => {
console.log(data);
}
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("minimalFrequency", { required: true })} />
{errors.minimalFrequency && "Only numbers are allowed"}
<input {...register("maximialFrequency", { required: true })} />
{errors.maximialFrequency && "Only numbers are allowed"}
<input type="submit" />
</form>
);
}
I would want to get the min and max values, in form of the given data object, of the user after they pushed the "submit" button and I just can't get my head around how it works.
My main component is a quite large class component, and I read that it might not work because react-hook-form needs a functional component. If true, is there a way to still use my class component somehow?
UPDATE: Added the parent component
import { useState } from "react";
import React from "react";
import BasicUsage from "./BasicUsage"
type Props = {
}
type State = {
dataFreq: object;
}
export default class Parent extends React.Component<Props, State>{
private timer: any;
constructor(props: Props) {
super(props);
this.state = {
dataFreq: {
minimalFrequency: 250,
maximialFrequency: 8000
}
};
}
getDataFromForm = (dataFreq: any) => {
this.setState({dataFreq: dataFreq })
console.log(dataFreq)
};
render() {
const minFreq = this.state.dataFreq;
console.log("This is a this dataFreq", this.state.dataFreq);
console.log("This is a this minimalFrequency", minFreq);
return (
<div>
<BasicUsage getDataFromForm={this.getDataFromForm}/>
</div>
);
}
}
You are still able to use your class component as a parent.
If I am I correct in assuming that you want to use data from the form in your main component, and the main component is the parent, you can define a function in your main component, something like
getDataFromForm(data){
this.setState({data: data })
}
Then you pass this function into your BasicUsage component
//In your main components render function, or wherever you are using the BasicUsage component
<BasicUsage
//other props you want to send into BasicUsage from the main component
getDataFromForm={getDataFromForm}
/>
Now in your BasicUsage component's onSubmit function you can call the function you passed as a prop as such
const onSubmit = (data: any) => {
//Do something with your data if you want to change format or process it somehow;
//in this case you should probably make a new variable and pass the new variable into getDataFromForm
props.getDataFromForm(data) //Call the function in the parent component
}
If you're using the form data in a sibling component and not a parent component, you would make the getDataFromForm function in a common parent and pass the function to the BasicUsage component and the state.data value into the sibling component where you want to access the data
I have already read all the stack-overflow questions related to this problem, also this official react post and the preferred solutions.
It's not recommended to use componentWillReceiveProps anymore!
Before you mark this question as duplicate, please understand my specific question, I didn't see any solution for my specific problem.
What I'm trying to do is very simple:
I have component KInputRange that received the value from props and send the value out (callback) onEnter event (will send the value to server only on enter)
The props.value can randomly change (coming by websocket from the server)
My Question:
Inside my components, the <input> value attribute will get the data from props or from state?
If from props:
How can I update the value internally when the user type input data?
If from state:
How can I update the new value if the props.value has change randomly from the server?
I'm actually need to update my internal state on props change
but how to do it today, if react says that's anti-pattern?
This my code so far:
class KInputRange extends React.Component<any, any> {
constructor(props: any) {
super(props);
}
private onKeyDown(e: any): void {
//If the key is enter call to props.onEnter with the current value
}
private onChange(e: any): void {
//if user change the value- change the internal value
}
public render() {
return (
<input value={?????} type="text" onChange={(e) => this.onChange(e)} onKeyDown={(e) => this.onKeyDown(e)}/>
);
}
}
Usage:
<KInputRange value={this.state.dataFromTheServer} onEnter={(val: number) => this.kInputRangeEnterClicked(val)}/>
You can use a function component as mentioned in the post you linked here.
To update the value internally you can use React's State Hook.
Something like this:
import React, { useState } from 'react';
const KInputRange = (props) => {
const [value, setValue] = useState(props.value);
function onKeyDown(e: any): void {
//If the key is enter call to props.onEnter with the current value
}
function onChange(e: any): void {
setValue(e.target.value);
}
return (
<input value={value} type="text" onChange={(e) => this.onChange(e)} onKeyDown={(e) => this.onKeyDown(e)}/>
);
}
First, as #Atul said, you DO need to use getDerivedStateFromProps.
It's all because you need to control your component value depending on both - props and internal state.
Assuming you using flow this code should help:
// #flow
import * as React from "react";
type Properties = {
remoteValue: string,
onSubmit: (value: string) => void
};
type State = {
remoteValueMemo: string,
internalValue: string
};
class KInputRange extends React.Component<Properties, State> {
static defaultProps = {
remoteValue: "",
onSubmit: () => {}
};
state = {
remoteValueMemo: this.props.remoteValue,
internalValue: this.props.remoteValue
};
static getDerivedStateFromProps(props: Properties, state: State) {
if (state.remoteValueMemo !== props.remoteValue) {
return {
remoteValueMemo: props.remoteValue,
internalValue: props.remoteValue};
}
return null;
}
handleValueChange = (event: SyntheticEvent<HTMLInputElement>) => {
this.setState({internalValue: event.currentTarget.value});
};
handleKeyDown = (event: SyntheticKeyboardEvent<HTMLInputElement>) => {
if (event.keyCode === 13) {
this.props.onSubmit(this.state.internalValue);
}
};
render(): React.Node {
const {internalValue} = this.state;
return (
<input value={internalValue} onChange={this.handleValueChange} onKeyDown={this.handleKeyDown}/>
);
}
}
export default KInputRange;
The argument passed to useState is not used to update the state on re-render.
You should use the useEffect Hook.
import React, { useEffect, useState } from 'react';
const Test = (props) => {
const [value, setValue] = React.useState({...props.value});
useEffect(() => {
setValue(props.value);
}, [props.value])
//...
}
Similar topic here: React.useState does not reload state from props
You can use useEffect hook of react whenever you need to do something on specific props change in function component
useEffect(() => {
// You can place your logic here to run whenever value changes
},[value]);
[value] is a dependency so that whenever the value changes you useEffect hook calls
Hope above is helpful to you.
My code is here: https://stackblitz.com/edit/react-8g3p3l
There are 2 dumb components:
insertion_citylist.jsx with the following code:
insertion_shoplist.jsx with the following code:
I expect the change on the selected city from the inseriton_citylist.jsx will trigger change on the shop list in insertion_shoplist.jsx. So my container component, app.js contains a function findShops, where the action shoplist(city) is called.
My container component code, app.jsx, is the following:
import React, { Component } from "react";
import { connect } from "react-redux";
import { citylist, shoplist } from "../actions";
import { bindActionCreators } from "redux";
import CityList from "../components/insertion_citylist";
import ShopList from "../components/insertion_shoplist";
class App extends Component {
componentDidMount() {
console.log("mount");
this.props.citylist();
this.props.shoplist();
}
findShops(city) {
console.log("findShops:", city);
this.props.shoplist(city);
}
/* renderShops = shops =>
shops
? shops.map(shop => <option key={shop.id} value={shop.name} />)
: null; */
render() {
console.log("render:" + this.props);
return (
<div>
<CityList data={this.props.data} findShops={this.findShops.bind(this)} />
<ShopList {...this.props} />
{/* <input list="shop" placeholder="shop" />
<datalist id="shop">
{this.renderShops(this.props.shop_data.shops)}
</datalist> */}
</div>
);
}
}
const mapStateToProps = state => {
console.log("map state to props:" + state.shops);
return { data: state.insertion_data }; //Use of spread operator: https://www.youtube.com/watch?v=NCwa_xi0Uuc&t=1721s
//return { city_data: state.cities, shop_data: state.shops };
};
const mapDispathToProps = dispatch => {
console.log("map dispatch to props");
return bindActionCreators({ citylist, shoplist }, dispatch);
};
export default connect(
mapStateToProps,
mapDispathToProps
)(App);
The `findShops` can be called successfully when the city from the downdown list is changed, but seems that the `this.props.shoplist()` just called the action without calling the *reducer*. And the actions code from `actions/index.js` looks like this:
export function citylist() {
return { type: "CITY_LIST", payload: [{city:"Berlin"}, {city: "Frankfurt"}] };
}
export function shoplist(city) {
let data = [{name:"original"},{name:"original 2"}];
if (city === 'Frankfurt') data=[{name:"new"},{name:"new 2"}];
return {
type: "SHOP_LIST",
payload: data
};
}
Problem: The current code is able to trigger the event handler findShops(), but does not succeed in changing the city list state and thus the city list on the insertion_citylist.jsx just keeps unchanged all the while. Could anyone help on this?
Thanks in advance!
it turns out very simple issue
onChange={(e) => props.findShops(e)}
here you are passing e as paramenter
findShops(city) {
this.props.shoplist(city);
}
and using it directly, this is invalid as you will have event in your city parameter.
you need e.target.value
change
<select name="city"
onChange={(e) => props.findShops(e)}>{renderCities(props.data.cities)}</select>
to
<select name="city"
onChange={(e) => props.findShops(e.target.value)}>{renderCities(props.data.cities)}</select>
Demo,
remember react pass an event when you change the value, you need to extract the value when you are reading from it. like you are doing in javascript or jquery.
for checkboxes its e.target.checked and for inputs its e.target.value.
i tried to use officejs react component in it and for osme reason i cant get it to work properly..effective here is the code. it works in codepen but when i put hte same code in excel addin project, i cant get the value in the textfields.
Code in codepen(it works):
[https://codepen.io/manish_shukla01/pen/ReWWmM][1]
Code in my project in app file(does not work in the sense that handlechange events are not getting fired i believe so value of my state.value1 remains blank even when i input anything):
import * as React from 'react';
import { Button, ButtonType } from 'office-ui-fabric-react';
import Header from './Header';
import { TextField } from 'office-ui-fabric-react/lib/TextField';
import * as OfficeHelpers from '#microsoft/office-js-helpers';
export default class App extends React.Component<any,any,any>{
constructor(props) {
super(props);
this.state = {
value1: '',
value2:'',
message:'Helloooo'
};
this.handleChange1 = this.handleChange1.bind(this);
this.handleChange2 = this.handleChange2.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange1(event) {
this.setState({value1: event.target.value});
}
handleChange2(event) {
this.setState({value2: event.target.value});
}
handleSubmit = async () => {
event.preventDefault();
this.setState({message: 'i got clicked'});
try {
//event.preventDefault();
await Excel.run(async context => {
/**
* Insert your Excel code here
*/
const range = context.workbook.getSelectedRange();
// Read the range address
range.load('address');
// Update the fill color
range.format.fill.color = 'blue';
range.values = [[this.state.value2]];
await context.sync();
console.log(`The range address was ${range.address}.`);
});
} catch(error) {
OfficeHelpers.UI.notify(error);
OfficeHelpers.Utilities.log(error);
};
}
render() {
return (
<form className='ms-welcome' onSubmit={this.handleSubmit}>
<Header logo='assets/logo-filled.png' title='Excel Analytics' message={this.state.message} />
<TextField label="field1"
value={this.state.value1} onChange={this.handleChange1}
required
/>
<Button className='ms-welcome__action' buttonType={ButtonType.primary}
onClick={this.handleSubmit}>Run
</Button>
</form>
);
}
}
I also faced same issue with Office UI Fabric TextField's "onChange" event and solved it using "onChanged" instead, which is deprecated as they say. But it worked for me.
First, add onChanged handler to TextField as below:
<TextField name="fieldName" label="field1" value={this.state.value1} onChanged={val => this.handleChange1("fieldName", val)} />
Also, note that "name" attribute is added to identify control in handleChange1.
Now change handler implementation as below:
handleChange1(name, value) {
this.setState(prevState => ({
result: {
...prevState.result,
[name]: value
}
}));
}
Hope this helps. Thanks!
I'm using SelectField of material-ui for my react project.
I have tried many ways from this answer Can't get the target attributes of material-ui select react component
.
But they don't work.My target.id always equals ""
How can I get the attributes (like id).
Here is my code:
constructor(props) {
super(props);
this.state = {
form: {
resident_city: ''
},
ret_code: '',
ret_msg: ''
};
this.handleList = this.handleList.bind(this);
}
handleList(event, index, value) {
event.persist()
const field = event.target.id;
const form = this.state.form;
form[field] = value;
console.log(event, value)
this.setState({
form
});
console.log(form);
}
<form>
<SelectField
style={style}
id="city"
value={this.state.form.resident_city}
onChange={this.handleList}
maxHeight={200}
>
{cities}
</SelectField>
</form>
Update
I tried to use SelectField without form,and I still can't get the id attributes.It is really confusing me.
On the main component you define a prop name for select the form component let say your city component is called : cityForm
in your cityForm component
render() {
return (
<SelectField
style={style}
value={this.props.city}
onChange={(e, index, value) => this.props.selectChange(e, index, value, this.props.cityName)}
maxHeight={200}
>
{cities}
</SelectField>
);
}
}
In your main comp you will have let say (code is cutted some part omitted)
handleSelectChange(e, index, value, name){
this.setState({
[name] : value,
});
}
render(){
return (
<cityForm cityName = "city1" city={this.state.city1} selectChange={this.handleSelectChange}/>
);
}
}
Im building a dynamic form generator and it did the trick for me =).
If a React class component is used, selected value can be accessed through its state object.
Alternatively, with help of Redux the Select's onChange method can dispatch an action and update the value in the main application state.
In cases when updating the main state isn't feasible and function component is chosen instead of a class component, getting the value from the component outside the function becomes cumbersome.
An easy way to fix it would be to add a hidden input referencing the same value as select uses. Consider the following piece of code. It uses Selector field1 to update value through internal component state and binds it to the hidden field theField. The value can be further read an outside function during dispatch just like any other input field value in the form.
import React, { useState } from 'react';
import { Button, FormControl, MenuItem, Select } from '#material-ui/core';
import { connect } from 'react-redux';
const mapStateToProps = () => ({
});
const mapDispatchToProps = (dispatch, ownProps) => ({
submitForm: (event) => {
event.preventDefault();
console.log(event.target.theField.value);
dispatch({
type: 'UPDATE_THE_FIELD',
theField: event.target.theField.value,
});
}
});
function Main(props) {
const [field1, setField1] = useState("v1");
return (
<>
<form onSubmit={(event) => { props.submitForm(event, props) }}>
<FormControl>
<Select
value={field1}
onChange={(event) => setField1(event.target.value)}
>
<MenuItem value="v1">V1</MenuItem>
<MenuItem value="v2">V2</MenuItem>
</Select>
</FormControl>
<Button type="submit">Update</Button>
<input type="hidden" name="theField" value={field1} />
</form>
</>
);
}
export default connect(mapStateToProps, mapDispatchToProps)(Main);