Cannot read property 'someProperty' of undefined in react - javascript

I am working on an application where I pass variable values in a Navlink using state from one component to the other and then load those received values in input fields and click on submit button in that other component to do something with values. My values are received correctly and show up correctly when I alert them. But when I click submit button, it gives error,pointing at the constructor
TypeError: Cannot read property 'id' of undefined
Here is my code
class Parent extends React.Component{
constructor(props) {
super(props);
this.state={id:2}
}
render(){
return(
<NavLink
to={{
pathname: '/Child',
state: {
id: this.state.id
}
}}
>
Edit
</NavLink>
)
)
}
Where I receive the values
class Child extends React.Component{
constructor(props) {
super(props);
this.state = {id:this.props.location.state.id}
alert(this.props.location.state.id)//works fine
}
setId(e){
this.setState({id:e.target.value})
}
addOrEdit(){ //gives error
alert(this.state.id)
//do something
}
render(){
return(
<div>
<form>
<label>Id</label>
<input value={this.state.id} onChange={this.setId.bind(this)} type="text"/><br/>
<input type="submit" onClick={this.addOrEdit.bind(this)} ></input>
</form>
</div>
)
}
}

this.state = {id: this.props.location && this.props.location.state && this.props.location.state.id}
Should fix your issue that caused by times that this component called without this context or this line got excuted before location set.
(assuming you using withRouter for making location props be exist...)
Anyhow, and not related directly to your issue, it is bad practice to set initial value for state from props at constructor, consider manipulate state through life cycle either don't use state here and refer to props directly

I would suggest to just use arrow functions for setId and addOrEdit.
addOrEdit = (e) => {
// ...
}
And just call them:
onChange={this.setId}
onClick={this.addOrEdit}
https://medium.com/#machnicki/handle-events-in-react-with-arrow-functions-ede88184bbb
Also you are deriving state from prop.
It is better to just use the prop directly.
https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html

Related

Pass States between Components - ReactJS

I am trying to pass some states between components however the values are always undefined.
I have a component called Home. When the user types in their email and password to login I want to pass those states to my other component i.e. So I have the users login information. However, the console.log statements show they are undefined.
Home.js in render method
return (
<div>
<HomePage signInEmail={this.state.signInEmail} signInPassword={this.state.signInPassword}/>
<p>Account</p>
<button onClick={this.logout}>Logout</button>
</div>
);
Below is what I have tried for HomePage.js
constructor(props) {
super(props);
this.state = {
noResp: ''
}
}
componentDidMount() {
console.log('Component Mounted!');
console.log('this.props.signInEmail ' + this.props.signInEmail );
console.log('this.props.signInPassword: ' + this.props.signInPassword);
}
The above comes to undefined. In my Home.js, I can get the values I need but I can't seem to pass these to a different component.
You can access it by
this.props.signInEmail
this.props.signInPassword
in your HomePage.js.
When you want to pass some data from parent to child component, they are called props.
Perhaps this help! State and Props in React
You can recieve props from parent component by writing
class HomePage extends React.Component{
constructor(props){
super(props);
}
render(){
return(//THE JSX you wanna return)
}
}
in the child component i.e., HomePage.js in your case!

How to access the props in react component?

import React, { Component } from 'react';
class newsList extends React.Component {
render(){
return(
<div>
{JSON.stringify(this.props.arr)}
</div>
)
}
}
export default newsList;
In the above code, arr is an object coming from another component. I can display the data using JSON.stringify(this.props.arr.result). But as soon as I change it with JSON.stringify(this.props.arr.result.id), I am getting an error says TypeError: this.props.arr.result is undefined. I cannot understand what I am doing wrong here?
I'm almost positive that, at some point in time, your this.props.arr is undefined, but then eventually gets assigned a value. Your initial render will receive a null or undefined, but if you try and go one step further into a key that doesn't exist, you will throw that error. You can use a boolean to control what gets initially rendered.
Instead of this line of code:
{JSON.stringify(this.props.arr)}
try this:
{this.props.arr ? JSON.stringify(this.props.arr) : null}
edit: is your issue with this.props.arr.result.id? If so, use this instead
{this.props.arr.result ? JSON.stringify(this.props.arr.result.id) : null}
Is this.props.arr Array?
If it is, the render function should be
render(){
var ids = this.props.arr.map(e=>(<div>e.result.id</div>))
return(
<div>
{ids}
</div>
)
}
Try out this code instead:
class NewsList extends React.Component {
constructor(props) {
super(props);
this.props = props;
}
render() {
return <div>{this.props.arr}</div>;
}
}
A React.Component's constructor always receives props as it's first parameter.

ReactJs print value of input field

I'm trying to print instantly my input value in the render function.
In the documentation of the concept of state and lifecycle in a React component, I see the use of a constructor with a super(props) as well as this.state.
I get the error below when trying same;
Uncaught TypeError: Cannot read property 'state' of undefined
Below is my code;
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
text: ''
};
};
handleChange(event) {
this.setState({
text: event.target.value
});
};
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.text}.</h2>
<input type="text" onKeyUp={this.handleChange} />
</div>
);
}
}
How can I fix it?
when you call a function like that, it is called by the window, not by your react object.
To make the function be bound to your react object (and have the ability to use the setState method, you need to use this:
onKeyUp={this.handleChange.bind(this)}
this will bind it to your react object :)
You have to bind this to your event handler like this:
<input type="text" onKeyUp={this.handleChange.bind(this)} />
Working Example: https://codepen.io/shanedaugherty/pen/ALwAzL
this.handleChange = this.handleChange.bind(this);
You can bind it like this in constructor and it will work, as you have to bind this to your react function.
You use value as an attribute.
value={this.state.text}
OR

ReactJS - How to properly initialize state from props which is populated by fetching data?

Here is my editing component:
class EditField extends React.Component {
constructor(props) {
super(props);
this.state = { value: '' };
}
edit(e) {
this.setState({ value: e.target.value });
if (e.keyCode === 13) {
this.props.onEdited(this.state.value);
}
}
render() {
return (
<div>
<input
type="text"
value={this.state.value}
onChange={this.edit.bind(this)}
/>
</div>
)
}
}
I need to populate state from props like this:
function Container({ entity, onEdited }) {
return (
<div>
<EditField onEdited={onEdited} value={entity.firstName} />
<EditField onEdited={onEdited} value={entity.lastName} />
</div>
);
}
The Container component get onEdited and entity props from redux store.
Container's parent will handle data fetching and onEdited (which will
only be triggered if user hit Enter) will dispatch request to the server.
My problem is how to initialize value props properly? Because if I use:
componentDidMount() {
this.setState({
value: this.props.value
});
}
I got empty state because fetching data is not finished when componentDidMount
called. And if I use:
componentWillReceiveProps(nextProps) {
this.setState({
value: nextProps.value
});
}
I got this warning:
Warning: EditField is changing a controlled input of type text to be
unncontrolled. Input elements should not switch from controlled to
uncontrolled (or vice versa). Decide between using a controlled or
uncontrolled input element for the lifetime of the component.
So, how to do this correctly?
This is what I recommend:
You could use getInitialState from EditField to populate the value state from the value prop. But this won't work, because getInitialState will only be called once, so subsequent renders will not update the state. Besides, this is an anti-pattern.
You should make the EditField component controlled. Always pass the current value as prop and stop dealing with state at all. If you want a library to help you link the input state with Redux, please take a look at Redux-Form.
The onEdited event you created, at least the way you did it, doesn't play well with controlled inputs, so, what you want to do is to have an onChange event that is always fired with the new value, so the Redux state will always change. You may have another event triggered when the user hits enter (e.g onEnterPressed), so you can call the server and update the entity values. Again. Redux-Form can help here.
Apparently entity.firstName and entity.lastName can only contain the values that the user has confirmed (hit enter), not temporary values. If this is the case, try to separate the state of the form from the state of the entity. The state of the form can be controlled by Redux-Form. When the user hits enter, you can trigger an action that actually calls the server and updates the state of the entity. You can even have a "loading" state so your form is disabled while you're calling the server.
Since Container subscribes to Redux store, I suggest make the EditField stateless functional component. Here's my approach:
const EditField = ({
onEdited,
value
}) => (
<div>
<input
type="text"
value={value}
onChange={onEdited}
/>
</div>
);
class Container extends React.Component {
constructor(props) {
super(props);
this.state = {value: ''};
}
edit = (e) => {
this.setState({value: e.target.value});
e.keyCode === 13 ? this.props.onEdited(this.state.value) : null;
};
sendValue = (val) => val ? val : this.state.value;
render() {
this.props = {
firstName: "Ilan",
lastName: null
}
let { firstName, lastName, onEdited } = this.props;
return (
<div>
<EditField onEdited={this.edit} value={this.sendValue(firstName)} />
<EditField onEdited={this.edit} value={this.sendValue(lastName)} />
</div>
)
}
}
ReactDOM.render(<Container />, document.getElementById('app'));
A live demo: https://codepen.io/ilanus/pen/yJQNNk
Container will send either firstName, lastName or the default state...

React: Controlling input value with both props and state

Given a React component with a controlled input, I would like to be able to:
Set the value of the input from the parent's state
Allow the user to change the input to any value
Update the parent's state only after the user submits and input passes validation.
I can accomplish 1 and 2 with the snippet below, but since the value came into the ChildComponent via props, I'm not sure how I can change the input value without changing the value of myInput on the parent.
class ChildComponent extends React.Component
{
render(){
return <input type="text" value={this.props.inputValue} onChange={this.handleChange.bind(this)} />
}
handleChange(e){
this.props.onInputChange(e.target.value);
}
handleSubmit(){
// do some validation here, it it passes...
this.props.handleSubmit();
}
}
class ParentComponent extends React.Component{
constructor(){
super();
this.state = {myInput: ""};
}
render(){
return <ChildComponent inputValue={this.state.myInput} onInputChange={this.handleChange.bind(this)} />
}
handleChange(newValue){
this.setState({myInput: newValue});
}
handleSubmit(){
// do something on the server
}
}
Then you just need to move the state to the child component, instead of rendering from props.inputValue directly. Basically you'd just move handleChange to the child.
Set the initial value from props.inputValue in getInitialState, then make sure to update the child state in componentWillReceiveProps.
componentWillReceiveProps is deprecated
Source: https://reactjs.org/docs/react-component.html#unsafe_componentwillreceiveprops
This lifecycle was previously named componentWillReceiveProps. That
name will continue to work until version 17. Use the
rename-unsafe-lifecycles codemod to automatically update your
components.
Use something like this instead:
componentDidUpdate(prevProps) {
if (this.props.yourObj != null && prevProps.yourObj !== this.props.yourObj) {
this.setState({
yourStateObj = this.props.yourObj
});
}
}

Categories