Why does it not push the element into the array state "tasks"? - javascript

I'm trying to create a todo app in React. I'm currently trying to print the input when i press the + button, but it is not working. Can anyone help to check my syntax!
import React from 'react';
import './App.css';
class App extends React.Component {
constructor(){
super();
this.state = {
value: '',
tasks: []
};
this.handleChange = this.handleChange.bind(this)
this.addItem = this.addItem.bind(this)
}
handleChange(event) {
this.setState({
value: event.target.value
})
}
addItem(){
this.state.tasks.push(this.state.value)
}
render(){
return(
<div>
<input type="text" value={this.state.value} onChange={this.handleChange}></input>
<button onClick={this.addItem}>+</button>
<button>-</button>
<h1>{this.state.tasks}</h1>
</div>
)
}
}
export default App;

To change the state you should use this.setState. Refer to https://reactjs.org/docs/state-and-lifecycle.html#do-not-modify-state-directly. Reading React documentation might save you a lot of time overall.

Modifying state directly is not the correct way!
instead use setState:
this.setState({
tasks: this.state.tasks.concat(this.state.value)
})

You need to setState task
addItem() {
const newTask = [this.state.value, ...this.state.tasks];
this.setState({ tasks: newTask });
this.setState({ value: "" });
}
enter image description here

Related

How do I can I use the array.push() method, so I can push data from one component into an array in a seperate file?

I have a component (Task.jsx) that recieves text data from the user, and that data needs to be pushed into an array, which is in it's own file (TaskData.js). How do I get get the input text pushed into the array? Not sure how to get the two files to talk to each other. Code as follows:
TaskData.js
const TaskData = [
{
id:8,
chore: 'wash dishes'
},
{
id:9,
chore: 'do laundry'
},
{
id:10,
chore: 'clean bathroom'
}
]
export default TaskData
Tasks.jsx
import React from 'react'
import TaskData from './TaskData.js'
class Tasks extends React.Component {
constructor(props) {
super(props)
this.state = {
updatedTask: '',
isEditing: false
}
this.handleClick = this.handleClick.bind(this)
this.handleChange = this.handleChange.bind(this)
}
handleClick () {
TaskData.push({id:50, chore: 'test'})
this.setState({
isEditing:true
})
}
handleChange (e) {
this.setState({
updatedTask: e.target.value
})
}
render() {
return (
<div className = 'tasks-container'>
<div>
{
this.state.isEditing ?
<input onChange = {this.handleChange} className = 'input' placeholder ={this.props.task}/>
: <h1 className = 'font'>{this.props.task}</h1>
}
<button onClick = {this.handleClick} className ='task-button'>Edit</button>
</div>
</div>
)
}
}
export default Tasks
Since react runs in the browser, you cannot write data into file. (You can read files though).
Note that in your handleClick when you do TaskData.push(...) you have mutated the array and you will have the updated data in the memory until you refresh the page. So you can use the TaskData variable access the updated data.
If you specifically want to write data to file, you can store it in localStorage or you can save file on the server.

ReactJS - TypeError: Cannot set property 'propOne' of undefined

I have a simple React component:
import React from "react";
export default class Car extends React.Component {
render() {
return <h2>I am a {this.props.name}</h2>;
}
}
I am then importing this component into another component. This new component has a textbox which onChange event, tries to set a property which is being passed as a property to component one.
import React from "react";
import Car from "./Car";
class Garage extends React.Component {
constructor(props) {
super(props);
this.propOne = "Ford";
this.state = { value: "initial Value" };
}
handleChange(event) {
this.propOne = event.target.value;
}
render() {
return (
<>
<input
type="text"
value={this.state.value}
onChange={this.handleChange}
/>
<Car name={this.propOne} />
</>
);
}
}
export default Garage;
After running this code, I am getting TypeError: Cannot set property 'propOne' of undefined error
It's because you are making a new function and creating a new instance of this. Change it to an arrow function -
handleChange = (event) => {
this.propOne = event.target.value;
}
Or you can bind the this of handleChange to parent's this in the constructor of class
constructor(props) {
super(props);
this.propOne = "Ford";
this.state = { value: "initial Value" };
this.handleChange = this.handleChange.bind(this);
}
Kudos to #Atin for mentioning changing your handleChange function to an arrow function or binding this (I'll use the arrow function in my answer).
You'll also need to set propOne in state, and use this.setState(...) to update the value of propOne so that your component re-renders when propOne changes. When you just change this.propOne, React doesn't know that your component needs to re-render with the updated value, which is why you don't see the effect in Car. -> that's what the state is for. Whenever state is changed (with this.setState), React knows it needs to re-render that component, and it will pass your updated state property down to child components.
Try this for your state:
this.state = { value: "initial Value", propOne: "Ford" };
And this for your handleChange function:
handleChange = (event) => {
this.setState({ propOne: event.target.value });
}
Edit:
Additionally, your code (and the above, fixed code) is setting a property propOne on the state, but you're using this.state.value to update your input text value. Is there any reason you're trying to use two different properties - value and propOne? It seems they're being used for the same purpose, and therefore you can replace propOne with value everywhere like this:
constructor(props) {
super(props);
this.state = { value: "initial Value" };
}
handleChange = (event) => {
this.setState({ value: event.target.value });
}
render() {
return (
<>
<input
type="text"
value={this.state.value}
onChange={this.handleChange}
/>
<Car name={this.state.value} />
</>
);
}
Referenced error is thrown because you didn't bind this.
Other than that, you have a bunch of errors in your code, so I tried to address them all at once. If you have further questions, feel free to ask in the comments:
const { render } = ReactDOM
class Car extends React.Component {
render() {
return <h2>I am a {this.props.name}</h2>
}
}
class Garage extends React.Component {
constructor(props) {
super(props)
this.handleChange = this.handleChange.bind(this)
this.state = { value: "initial Value", propOne: 'Ford' }
}
handleChange(val) {
this.setState({value: val, propOne: val})
}
render() {
return (
<div>
<input
type="text"
value={this.state.value}
onChange={e => this.handleChange(e.target.value)}
/>
<Car name={this.state.propOne} />
</div>
)
}
}
render(
<Garage />,
document.getElementById('root')
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script><div id="root"></div>
p.s. and I agree with above answers, function components and hooks could make your app look much nicer

Changing the state of a checkbox with setState

I have a component and i am able to change the state of checkbox item when i click on a button.
I also want to be able to change the state in another button-click, which has lot more logic in it.
The issue i am having in that when the code goes into the condition it does not set the state back to false.
I tried changing the state again using setstate but it does not change the state of the enabledCheckBox.
this.setState({
enabledCheckBox: !this.state.enabledCheckBox,
})
Can anyone tell me what the issue is?
Thanks
class Customer extends Component {
constructor(props) {
super(props)
this.state = {
...props,
enabledCheckBox: false
};
}
//this works
onChangeCheckBox=()=>{
this.setState({
enabledCheckBox: !this.state.enabledCheckBox,
})
}
//cant get this to work
handleCustomerClick = (event) => {
if (this.state.enabledCheckBox) {
this.setState({
enabledCheckBox: !this.state.enabledCheckBox,
})
}
https://codesandbox.io/s/1y0zywy727
I included a working example. It does similar things as how you described.
import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
enabledCheckBox: false
};
}
onClick = () => {
this.setState({ enabledCheckBox: !this.state.enabledCheckBox });
};
render() {
return (
<div>
<input
type="checkbox"
value={"some checked box"}
checked={this.state.enabledCheckBox}
onChange={this.onClick}
/>
{this.state.enabledCheckBox ? <div>Blue</div> : <div>Red</div>}
<button onClick={this.onClick}>Click to Change Color</button>
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Both input and div are using this.state.enabledcheckbox. So if you check the box, not only the box will be checked but also the div's "color" would change with it. Same thing as clicking the button
your this is being bound incorrectly try this;
handleCustomerClick = (event) => {
let {enabledCheckBox} = this.state;
this.setState({
enabledCheckBox: !enabledCheckBox,
});
}
If you really need the if statement you could do the following;
handleCustomerClick = (event) => {
let {enabledCheckBox} = this.state;
let data;
if (enabledCheckBox) {
data = {
enabledCheckBox: !enabledCheckBox
}
}
this.setState(data);
}

React: Accessing child component function but gives an undefined error

So basically I'm trying to access a function in a child node (that returns the input of a text-box), from the parent node but i keep on getting an error stating that the function is not a function.
MakeMethod.jsx:22 Uncaught TypeError: i.getState is not a function
at MakeMethod.jsx:22
at Array.map (<anonymous>)
at MakeMethod.getAllInfo (MakeMethod.jsx:22)
at onClick (MakeMethod.jsx:41)
I've tried using the ref prop but it doesn't seem to work with an array of components.
The methods/function used to return the props parameter from the child node is the getState() one.
The method/function used to store the list of inputs from the children is the getAllInfo() one.
Is there something I'm doing drastically wrong? If so Would you be able to point it out to me?
Many thanks in advance!!
The parent class is the MakeMethod:
import React from 'react';
import "./MakeRecipe.css";
import Steps from "./Steps.jsx";
const count=1;
const theSteps=[]; //list of step components i want to access
class MakeMethod extends React.Component {
constructor(){
super();
this.state = {
count : 1,
}
this.AddMethod = this.AddMethod.bind(this);
this.getAllInfo=this.getAllInfo.bind(this);
theSteps.push(<Steps key={this.state.count} count={this.state.count} value={''}/>);
}
//this is the function i want to access all my information from
getAllInfo(){
let method=[];
method=theSteps.map((i)=>
i.getState() //iterates through each Step component and calls on the function getState()
//but it says that the function does not exist
);
this.setState({steps:method});
console.log(method);
}
AddMethod(){
let x=this.state.count+1;
theSteps.push(<Steps key={x} count={x}/>);
this.setState({count:x});
}
render() {
return (
<div key={"method"}>
<div>
{theSteps}
</div>
<button onClick={()=>this.AddMethod()}>Add another method?</button>
<button onClick={()=>this.getAllInfo()}>checking info</button>
</div>
);
}
}
export default MakeMethod;
And the Child component is the Steps:
import React from 'react';
import "./MakeRecipe.css"
const count=1;
class Steps extends React.Component {
constructor(props) {
super();
this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.getState = this.getState.bind(this);
}
//function that returns the value in the text box
getState(){
debugger;
console.log(this.state.value); //tested and works
return this.state.value;
}
handleChange(event) {
this.setState({value: event.target.value});
}
handleSubmit(event) {
alert('A name was submitted: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<div>
<div id={this.props.count}>
<a>Step: {this.props.count}</a>
<input key={this.props.count} type="text" value={this.state.value} onChange={this.handleChange}/>
<br/>
</div>
<button onClick={()=>this.getState()}/>
</div>
);
}
}
export default Steps;
I think you don't exactly know the React lifecycle and how does really works passage from Parent to Child and vice versa.
This is a pseudo code that puts you in the right direction
import React from 'react';
import Steps from "./Steps";
const count=1;
const theSteps=[]; //list of step components i want to access
class MakeMethod extends React.Component {
constructor(props) {
super(props);
this.state = {
count : 1,
theSteps:[] ,
itemFromChild:''
}
this.AddMethod = this.AddMethod.bind(this);
this.getAllInfo=this.getAllInfo.bind(this);
this.state.theSteps.push(<Steps key={this.state.count} count={this.state.count} value={this.getAllInfo}/>);
}
//this is the function i want to access all my information from
getAllInfo=(itemFromChild)=> {
let method=[];
this.setState({ itemFromChild });
console.log(itemFromChild);
}
getAllInfoLocal() {
console.log(this.state.itemFromChild);
}
AddMethod(){
let x=this.state.count+1;
theSteps.push(<Steps key={x} count={x}/>);
this.setState({count:x});
}
render() {
return (
<div key={"method"}>
{this.state.itemFromChild}
<div>
{this.state.theSteps}
</div>
<button onClick={()=>this.AddMethod()}>Add another method?</button>
<button onClick={()=>this.getAllInfoLocal()}>checking info</button>
</div>
);
}
}
export default MakeMethod;
the other class...:
class Steps extends React.Component {
constructor(props) {
super(props);
this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.getState = this.getState.bind(this);
}
//function that returns the value in the text box
getState(){
debugger;
console.log(this.state.value); //tested and works
return this.state.value;
}
handleChange = (event) =>{
console.log(event.target.value)
this.setState({value: event.target.value});
this.props.value(event.target.value);
}
handleSubmit(event) {
alert('A name was submitted: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<div>
<div id={this.props.count}>
<a>Step: {this.props.count}</a>
<input key={this.props.count} type="text" value={this.state.value} onChange={this.handleChange}/>
<br/>
</div>
<button onClick={()=>this.getState()}/>
</div>
);
}
}
export default Steps;
Hope it helps...
Try to console log your component see what it will display.
Try i.getState. I think it should work since you're calling the property which is a function and not the callback of the function.
Also bind functions to the components like this:
getState = () => {
debugger;
console.log(this.state.value); //tested and works
return this.state.value;
}
since .bind has a lot of memory leaks.

How to change props of a child?

I am new to React. This is probably a noob question.
I want to change the "filteredFields" prop of my MeteorGriddle component when the user clicks a checkbox. My JSX:
const bookingsPage = () => {
let filteredFields = ['userName'];
const handleClick = (e) => {
if (e.target.checked) {
filteredFields = ['userEmail'];
// How to propagate this change to the MeteorGriddle?
}
}
return (
<div>
<label><input type="checkbox" defaultChecked="true" value="userEmail" onClick={handleClick}/>Email</label>
<MeteorGriddle filteredFields={filteredFields}/>
</div>
);
};
I see two ways of solving your problem.
The first and easy way to do this:
Turn your bookingsPage component into statefull component instead of functional,
then you'd be able to create state inside it, and then change the state on event alongside with passing it to MeteorGriddle component.
So the code would be:
class bookingsPage extends React.Component {
getInitialState = () => {
filteredFields: []
}
handleClick = (e) => {
if (e.target.checked) {
const newFilteredFields =
[ ...this.state.filteredFields ].push('userEmail');
this.setState({ filteredFields: newFilteredFields });
}
}
render() {
return (
<div>
<label>
<input
type="checkbox"
defaultChecked="true"
value="userEmail"
onClick={this.handleClick}
/>
Email
</label>
<MeteorGriddle
filteredFields={this.state.filteredFields}
/>
</div>
);
}
};
Second and harder way to do this:
Take a look on Redux. It solves a problem of data flow in React.
The basic concept is that when you check you checkbox, you dispatch an action into reducer (aka your global data storage for react components), and then GriddleComponent recieves new state of your application with fresh data inside which tells him the checkbox is checked.
Say if you want me to write an example based on yours for you.
As #Maxx says, you should use a component with state. Then when you call the setState method, it will render again, updating the props of the children.
In your case this should work (also using ES6 notation):
import React from 'react';
import MeteorGriddle from '...whatever path...';
class bookingsPage extends React.Component {
state = {
filteredFields: ['userName']
};
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
if (e.target.checked) {
this.setState({
...this.state, //This is just a good practice to not overwrite other properties
filteredFields: ['userEmail']
});
}
}
render() {
const { filteredFields } = this.state;
return(
<div>
<label>
<input type="checkbox" defaultChecked="true" value="userEmail"
onChange={this.handleChange}/>Email
</label>
<MeteorGriddle filteredFields={filteredFields}/>
</div>
);
}
}
There are number of ways to achieve this, you can just try like the below code,
import React from 'react';
class bookingsPage extends React.Component {
state = {
filteredFields: ['userName']
};
constructor(props) {
super(props);
}
handleChange(e) {
if (e.target.checked) {
this.setState({
filteredFields: ['userEmail']
});
}
}
render() {
return(
<div>
<label>
<input type="checkbox" defaultChecked="true" value="userEmail"
onChange={this.handleChange.bind(this)}/>Email
</label>
<MeteorGriddle filteredFields={this.state.filteredFields}/>
</div>
);
}}

Categories