Cannot read property 'enqueueSetState' of undefined in ReactJS - javascript

I'm not quite sure why I'm getting this error.
class ContentProcessing extends Component {
constructor(props) {
super(props);
this.state = {content: currentData};
this.setData = this.setData.bind(this);
}
setData(data) {
this.setState({
content: data
});
}
render() {
return (
<div>
<Card title={this.state.content} />
</div>
);
}
}
The error is reported at
this.setState({
content: data
});
Basically I'm launching setData from a Button in another class, as soon as I click it my page breaks and I receive the error.
I checked and it looks like in setData(), this.state is undefined so I suppose that's probably where the problem comes from.
I've looked at a few other answers that were having this same problem but their fixes don't seem to be working for me.

This error is because this.setState in not bind to this in main class. If you want to pass setState to somewhere else you need to bind it first in its main class:
class ContentProcessing extends Component {
constructor(props) {
super(props);
this.state = {content: currentData};
this.setData = this.setData.bind(this);
this.setState = this.setState.bind(this); // <- try by adding this line
}}

Inside your constructor you have:
this.state = {content: currentData};
Where does currentData come from? If it's supposed to be passed as a prop, then change that line to:
this.state = {content: prop.currentData};

I guess you are calling setData from Card component.
If this is the case, send setData as a prop to Card component
// Below code snippet in ContentProcessing component
<div>
<Card
title={this.state.content}
setData={this.setData}
/>
</div>
Now you can access setData method in Card component as prop.
// Call it in Card component
this.props.setData(data);

This setData is useless as it will just stay undefined all the time
setData(data) {
this.setState({
content: data
});
}
You can some sort of event which will be responsible for setState() Something like :
render() {
return (
<div>
<Card title={this.state.content} onClick={() => {this.setData}}/>
</div>
);
}
}

Related

Why the function argument returns undefined when using props?

I am building an app using react-native. I have 3 components namely Ind.js, Buttons.js, Rain.js. I am required to select an option in Rain and save it in the state of Ind for further processing. Since Rain component is not directly related to Ind but is connected via a navigation route in Buttons.
I am using react-navigation.
To do so I created a function onSelect() in Ind which does the setState and passed it to Buttons via props and passed again to Rain then I executed the function, the problem is the function is getting called but no parameters are passed ie, it console.logs null then undefined.
I have tried to console.log the parameters that are passed to Ind.
Ind.js
export default class Ind extends Component {
constructor(){
super();
this.state = { report: null}
}
onSelect = (newreport) => {
this.setState({
report: newreport
})
console.log("Parameter: ", newreport)
console.log("State: ", this.state.report)
}
render(){
return(
<Buttons selectReport={() => this.onSelect()}
)
}
}
Buttons.js
export default class Buttons extends Component{
constructor(props){
super(props);
}
render(){
return(
<TouchableOpacity
onPress={() => {this.props.navigation.navigate('Rain',{
selectReport: this.props.selectReport });
}}>
<Text style={styles.text}>Rain</Text>
</TouchableOpacity>
)
}
}
Rain.js
export default class Rain extends Component{
constructor(props){
super(props);
this.state = {
selection: "Test"
}
this.selectOption = this.selectOption.bind(this);
}
selectOption = () => {
this.props.navigation.state.params.selectReport(this.state.selection)
}
}
The console log return first Parameter: undefined State: null which is understandable because nothing is clicked but after clicking it shows
Parameter: undefined State: undefined.
What is happening? I am a beginner and is there something wrong in binding or sending the props?
Please Explain.
When working with arrow function, you need to call like,
<Buttons selectReport={() => this.onSelect} > //without parenthesis
also setState is async so you need to use callback in setState to print value.
You need to do this,
export default class Ind extends Component {
constructor(){
super();
this.state = { report: null}
}
onSelect = (newreport) => {
console.log("Parameter: ", newreport)
this.setState({
report: newreport
},()=> console.log("State: ", this.state.report)) //prints in callback
}
render(){
return(
<Buttons selectReport={() => this.onSelect}>
)
}
}
You didn't put any parameters in the click button. However, the function is receiving parameters as values. Of course it points to undefind.
onSelect = (newreport) => {
this.setState({
report: newreport
})
console.log("Parameter: ", newreport)
console.log("State: ", this.state.report)
return this.state.report;
}
render(){
return(
<Buttons selectReport={this.onSelect("value")}
)
setState is async function so that's why after the first click you get null (because it didn't change yet) however somewhere in your code passing value of newreport is wrong.

React function says "is not a function"

I'm working on breaking up a little react app into smaller components. Before separating code everything worked as planned. I now am trying to call a function onChange that calls a function and then that calls a function as a prop. I am binding the function like this this.updateInput = this.updateInput.bind(this); but I still cannot figure out what I am missing. I tried a recent post on here (React : Pass function to child component) but the error still remains. Any help is great.
Here is the code I am working with:
class Weather extends React.Component {
constructor(props) {
super(props);
this.state = {
city: '',
details: []
};
this.updateInputValue = this.updateInputValue.bind(this);
}
updateInputValue(e) {
this.setState({
city: e.target.value
});
console.log('hit')
}
render() {
return (
<div className={style.container + ' ' + style.bodyText}>
<WeatherForm
updateInput={this.updateInputValue}
/>
</div>
);
}
}
class WeatherForm extends React.Component {
constructor(props) {
super(props);
this.updateInput = this.updateInput.bind(this);
}
updateInput(e) {
this.props.updateInputValue(e);
}
render() {
return (
<div className={style.weatherForm}>
<form action='/' method='GET'>
<input ref='city' value={this.props.inputValue} onChange={e => this.updateInput(e)} type='text' placeholder='Search city' />
</form>
</div>
);
}
}
So when I type one character in the input, instead of the console logging hit, it says Uncaught TypeError: this.props.updateInputValue is not a function. What am I missing here?
It should be
<WeatherForm
updateInputValue={this.updateInputValue}
/>
Common related problem:
The same "is not a function" error can also be caused by mis-using the props, as shown in this question
Your child component only has the prop of updateInput as a method and you're calling this.props.updateInputValue() in child component. Try to call them the same names.
You're also calling this.props.inputValue in the child component when you're not passing inputValue into your child component as a props.
What I would do to simplify the code and possible avoid mistakes like this in the future is to directly call this.props.updateInputValue in onChange event like this:onChange={e => this.props.updateInputValue(e)}
You then save the work of binding another component method in constructor. It'll also make your unit testing easier but that's another discussion.

Fetch data and then render it to dom React

Hi I am fetching data from an api and I would like to take the data and render it to the dom but I am the error "Uncaught TypeError: Cannot read property 'map' of undefined at Topicselect.render"
Here is essentially what I am doing, although I have abstracted away anything that is not directly relevant to the question, such as actual topic names, imports, etc :
class Topics extends Component{
constructor(props){
super(props);
this.state = {
topics: []
}
}
componentWillMount(){
fetch('/api').then((res)=>r.json().then((data)=>{
// push topics into this.state.topics somehow
})
console.log(this.state.topics) //returns ['topic1','topic2','topic3'];
}
render(){
const list = this.state.topics.map((topic)=>{
return(<li>{topic}</li>);
})
return(
<ul>
{list}
</ul>
)
}
}
Can anyone tell me how to fix this? I saw an answer on here that said to use componentDidMount instead of componentWillMount but that isn't working for me
You are missing a closing bracket ) after the fetch and it's indeed recommended to use componentDidMount() instead of componentWillMount() for fetching data from an API.
Also don't forget to use this.setState({ topics: data.howeverYourDataIsStructured }); after you receive the data from the API to ensure a rerender of the component.
class Topics extends Component{
constructor(props){
super(props);
this.state = {
topics: []
}
}
componentDidMount() {
fetch('/api').then((res)=>r.json().then((data)=>{
this.setState({ topics: data.topics });
}));
console.log(this.state.topics) //returns [];
}
render() {
console.log(this.state.topics) //returns [] the first render, returns ['topic1','topic2','topic3'] on the second render;
return(
<ul>
{this.state.topics.map(topic => (
<li>{topic}</li>
))}
</ul>
)
}
}
Make sure you use setState() to update your state, otherwise render() won't be triggered to update the dom. Also make sure you don't just overwrite the current state but add your new topics to the old ones. (not relevant for this case, but still important to mention)
One way to do it would be:
componentDidMount() {
var currentTopics = this.state.topics;
fetch('/api').then((res) => r.json().then((data) => {
currentTopics.push(data);
}));
this.setState({'topics': currentTopics});
}
But you can also call setState() inside the loop. setState() does not work synchronously so it will first wait if there are some other changes to be made before it will actually execute the changes and then trigger render.
componentDidMount() {
fetch('/api').then((res) => r.json().then((data) => {
this.setState((state) => ({ topics: [...state.topics, data]}));
}));
}

componentWillReceiveProps on react does not pass the current property when ever it triggers

Hello guys I'm new to react
I'm working with react component passing a property from a state of parent component and I'm not sure why i get an undefined property error whenever i trigger and event from the parent component
You can visit the code here# https://codepen.io/private_ryan/pen/RVBdpO?editors=0011#live-view show console and click the edit button
SampleTable Component
constructor(props, context) {
super(props);
this.state = { UPD:[] };
}
updateRow(x) {
var array = this.state.TRs;
var index = array.findIndex(e => e.id == x);
this.setState({
UPD: this.state.TRs[index]
});
}
render() {
return (<AddFormData onAdd={ this.onAddForm }
upd={ this.state.UPD }
updcan={ this.cancelUpd }
propUpd= { this.propcessUpd } />
<button onClick={ this.updateRow} value={ some.id } >click me</button>
);
}
AddFormData Component
constructor(props) {
super(props);
this.state = { textName: '', textArea: '' };
}
componentWillReceiveProps(){
console.log( this.props ) // undefined no props when first click
// set the state here
}
New props are received as parameters to the function:
componentWillReceiveProps(nextProps)
https://facebook.github.io/react/docs/react-component.html#componentwillreceiveprops
componentWillReceiveProps will get called whenever you do any changes in props values in parent component, new values will get passed as parameter and after this lifecycle method this.props will get updated so if you do console.log(this.props) inside this it will log the previous value not the new one.
Use this:
componentWillReceiveProps(newProps){
console.log(this.props.upd.id, newProps)
}
Check the working example.

Prepopulate controlled components

In my attempt to handle an update form, have written the code below. It is a controlled input component, with a corresponding state value. When a change happens on the input component the state value is updated. This means view will always reflect data changes and the other way around. My issue comes when trying to prepopulate the input component with data fetched from the database. My attempt was to define the initial state value in the constructor, to be equal to the passed props, but that did not work. When the component is first rendered it will not contain the passed spirit prop, since it has not yet been fetched. When the component is rendered the second time (because the data is ready) the constructor will not be called. How will I set the initial state when the data is ready and not before?
SpiritsEditContainer
export default createContainer(({params}) => {
const handle = Meteor.subscribe("spirit", params.id);
return {
loading: !handle.ready(),
spirit: Spirits.find(params.id).fetch()[0]
}
}, SpiritsEditPage);
SpiritsEditPage
export default class SpiritsEditPage extends Component {
constructor(props) {
super(props)
this.state = {name: this.props.spirit.name}
}
handleNameChange(event) {
this.setState({name: event.target.value});
}
handleUpdate(event) {
event.preventDefault();
}
render() {
const {name} = this.state;
if (this.props.loading) {
return <div>loading</div>
} else {
return (
<div>
<h1>SpiritsEditPage</h1>
<form onSubmit={this.handleUpdate.bind(this)}>
<Input type="text"
label="Name"
value={name}
onChange={this.handleNameChange.bind(this)}/>
<button>Update</button>
</form>
</div>
)
}
}
}
The constructor code may not work correctly:
constructor(props) {
super(props)
this.state = {name: this.props.spirit.name}
}
Instead check for props.spirit to be available.
this.state = { name: this.props.spirit && this.props.spirit.name }
Add a componentWillReceiveProps:
componentWillReceiveProps(nextProps) {
if (nextProps.spirit !== this.props.spirit) {
this.setState({ name: nextProps.spirit.name });
}
}
The rest of the code looks alright.

Categories

Resources