onchange input and set state not working? - javascript

I'm working on simple form element using react-js.
There are three component:
App
TakeInput
Index
problem is when user put text in input field setState() function not work properly and data not updated. For testing purpose when i'm placing console.log in app js component it shows undefined on console. anyone sort this please. I want to console the updated data when state update
App.js
import React, { Component } from 'react';
import InputField from './TakeInput';
class App extends Component {
state = {
userInp : '',
outText : ''
}
handlechanger2 = (v) => {
this.setState( () => ({
userInp: v,
}))
console.log(this.userInp);
}
render() {
return (
<div className="App">
<InputField changingVal={this.handlechanger2}/>
</div>
);
}
}
export default App;
TakeInput.JS
import React, { Component } from 'react';
class TakeInput extends Component{
state={
txt: ''
}
handlerChange = (e)=>{
const { changingVal } = this.props;
const v = document.getElementById("userInput").value;
changingVal(v);
// console.log(e.target.value);
this.setState({ txt: e.target.value })
}
render(){
return(
<input type="text" name="userInput" id="userInput" placeholder="Please Enter Text" onChange={this.handlerChange} value={this.txt}/>
)
}
}
export default TakeInput;
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import * as serviceWorker from './serviceWorker';
ReactDOM.render(<App />, document.getElementById('root'));
serviceWorker.unregister();

it is about you are developing wrong way. I think you text input should be at your parent component
To read from state you should use this.state.abc
import React, { Component } from 'react';
class TakeInput extends Component{
handlerChange = (e)=>{
this.props.onChange(e.target.value);
}
render(){
return(
<input type="text" name="userInput" placeholder="Please Enter Text" onChange={this.handlerChange} value={this.props.txt}/>
)
}
}
export default TakeInput;
import React, { Component } from 'react';
import InputField from './TakeInput';
class App extends Component {
state = {
userInp : '',
outText : ''
}
handlechanger2 = (v) => {
this.setState( () => ({
userInp: v,
}))
console.log(this.state.userInp);
}
render() {
return (
<div className="App">
<InputField txt={this.state.userInp} onChange={this.handlechanger2}/>
</div>
);
}
}
export default App;

You're trying to console.log this.userInp. It should be this.state.userInp.
Also to see the update right after the last set state, you can do the following:
handlechanger2 = (v) => {
this.setState( () => ({
userInp: v,
}), function(){ console.log(this.state.userInp);}) // set a callback on the setState
}

Related

React not rendering the array

I am new to react and trying to create a simple todo list to understand React states and props but cant seem to understand why its not rendering the array on the screen. When the button is pressed it console logs the array of the inputs so I know that works.
here is each component currently there are no errors just nothing shows up.
App.js:
import React from "react";
import ControlPanel from "./ControlPanel";
import TodoList from "./TodoList";
class App extends React.Component {
state = { TodoList: [] };
addTask = (todoItem) => {
this.setState({ TodoList: [...this.state.TodoList, todoItem] });
console.log(this.state.TodoList);
};
render() {
return (
<div>
<ControlPanel addTask={this.addTask} />
<TodoList todoitem={this.state.TodoList} />
</div>
);
}
}
export default App;
ControlPanel.js:
import React from "react";
class ControlPanel extends React.Component {
state = { todoItem: "" };
addItem = (event) => {
event.preventDefault();
this.props.addTask(this.state.todoItem);
};
render() {
return (
<div className="ui card">
<div className="ui input">
<input
onChange={(e) => {
this.setState({ todoItem: e.target.value });
}}
value={this.state.todoItem}
type="text"
placeholder="Todo List Item"
/>
</div>
<div>
<button onClick={this.addItem} className="ui button">
Add Item
</button>
</div>
</div>
);
}
}
export default ControlPanel;
TodoList.js:
import React from "react";
import TodoItem from "./TodoItem";
const TodoList = (props) => {
const todoItems = props.TodoList?.map((todo) => {
return <TodoItem TodoItem={TodoItem} />;
});
return <div>{todoItems}</div>;
};
export default TodoList;
TodoItem.js
import React from "react";
const TodoItem = (props) => {
return <div>{this.props.TodoItem}</div>;
};
export default TodoItem;
import React from "react";
import TodoItem from "./TodoItem";
const TodoList = (props) => {
const todoItems = props.TodoList?.map((todo,idx) => {
return <TodoItem TodoItem={todo} key={idx} />; // idx or any unique key
});
return <div>{todoItems}</div>;
};
export default TodoList;
More information for key
https://reactjs.org/docs/lists-and-keys.html

Why is my text not changing as I'm writing text to the input tag in React

My code from App.js. The idea is that when you enter text in input the screen should be updated accordingly. For some reason set state isn't working and I don't know why.
import React, { Component } from 'react';
import UserOutput from './Components/UserOutput';
import UserInput from './Components/UserInput';
class App extends Component {
state = {
username: 'Adib',
};
changeUsername = (event) => {
this.setState({
username: event.target.value,
});
};
render() {
return (
<div className="App">
<UserInput changed={this.changeUsername} />
<UserOutput name={this.state.username} />
</div>
);
}
}
export default App;
My code from useroutput.js
import React from 'react';
const userOutput = (props) => {
return (
<div>
<p>Username: {props.name}</p>
<p>Hello {props.name}</p>
</div>
);
};
export default userOutput;
My code from userinput.js
import React from 'react';
const userInput = (props) => {
return <input type="text" onChanged={props.changed} />;
};
export default userInput;
You are using onChanged as the name of the event action on the input field in the userInput Component. replace it with
return <input type="text" onChange={props.changed} />;
Your UserInput component is using an onChanged event which is not a valid event in React, try using onChange instead.
import React from 'react';
const userInput = (props) => {
return <input type="text" onChange={props.changed} />;
};
export default userInput;

React Props for Handle Change not a Function

I'm getting props.handleChange is not a function when running the following code. I'm trying to update the state when the checkbox is clicked. The field that is check box is called myNetwork. I thought that when NetworkArray component, which is a parent of Card component, would have access to the functions and state in App? But this is my first React App. Please, what am I doing wrong?
App.JS
import React, {Component} from 'react';
import SignUp from './components/SignUp';
import NetworkArray from './components/NetworkArray';
import {network} from './NetworkData'
import './App.css';
import 'tachyons';
class App extends Component {
constructor() {
super()
this.state = {
network: network,
}
this.handleChange=this.handleChange.bind(this);
}
handleChange(id) {
this.setState(prevState => {
const updatedNetwork = prevState.network.map(netw => {
if (netw.id===id) {
netw.myNetwork = !netw.myNetwork
}
return netw
})
return {
network:updatedNetwork
}
})
}
render() {
return (
<div>
<NetworkArray
network={network}
handleChange = {this.handleChange} />
</div>
);
}
}
export default App;
Card.js
import React from 'react';
const Card = (props) => {
return(
<div className = 'bg-light-green dib br3 pa3 ma2 grow shadow-5'>
<div>
<h3>{props.name}</h3>
<p>{props.company}</p>
<p>{props.phone}</p>
<p>{props.email}</p>
<p>{props.city}</p>
</div>
<div>
MyNetwork
<input
type = "checkbox"
checked={props.myNetwork}
onChange={()=> props.handleChange(props.id)}
/>
</div>
</div>
)
}
export default Card;
NetworkArray.js
import React, {Component} from 'react';
import Card from './Card';
const NetworkArray = ({network}) => {
const cardComponent = network.map((user,i) => {
return(
<Card
key = {network[i].id}
name = {network[i].firstName + ' ' + network[i].lastName}
company = {network[i].company}
phone= {network[i].phone}
email={network[i].email}
city = {network[i].city}
/>
)
})
return (
<div>
{cardComponent}
</div>
)
}
export default NetworkArray;
You passed the function from App component to NetworkArray component, but not to Card component.
const NetworkArray = ({network, handleChange}) => {
...
<Card
handleChange={handleChange}
...
/>
}

State is not defined

I'm new to react and I'm getting an error for the state and method:
./src/App.js
Line 5: 'state' is not defined no-undef
Line 8: 'inputchangehandler' is not defined no-undef
This is my code until now:
import React from 'react';
import './App.css';
function App() {
state = {
userInput: ''
}
inputchangehandler = (event) => {
this.setState = ({
userInput: event.target.value
})
}
return (
<div className="App">
<input type="text" name="name"
onChange={this.inputchangehandler}
value = {this.state.userInput}/>
</div>
);
}
export default App;
In react there are 2 types of components.
Functional Components(like you used)
Class Components
Functional Components are stateless(in older versions, you can use hooks now) components. So if you want to directly use state you should change your components to class based component like this:
import React, { Component} from 'react';
import './App.css';
class App extends Component {
state = {
userInput: ''
}
inputchangehandler = (event) => {
this.setState = ({
userInput: event.target.value
})
}
render(){
return (
<div className="App">
<input type="text" name="name"
onChange={this.inputchangehandler}
value = {this.state.userInput}/>
</div>
);
}
}
export default App;
Functional component don't have state, form React 16.8 we have Hooks.
You should use useState hook for state.
import React, {useState} from 'react';
const [userInput, setUserInput] = useState('')
Usage,
<input type="text" name="name"
onChange={inputchangehandler}
value = {userInput}/>
inputchangehandler function should be,
const inputchangehandler = (event) => {
setUserInput(event.target.value)
}
Demo
Note: Functional component don't have access to this.
You have created functional component which does not have state. Define App as class component like below :
import React, { Component } from 'react';
import './App.css';
class App extends Component {
constructor(props) {
super(props);
this.state = {
userInput: ''
}
}
inputchangehandler = (event) => {
this.setState = ({
userInput: event.target.value
})
}
render() {
return (
<div className="App">
<input type="text" name="name"
onChange={this.inputchangehandler}
value={this.state.userInput} />
</div>
);
}
}
export default App;
You need to define state in your class's constructor like below:
constructor(props) {
super(props);
this.state = {
userInput: ''
}
}
Declaring your component as a function you don't have state.
Try converting it in class component or in a function using Hooks according to react documentation.
If you are using React version greater than 16.8 then you can use the useState hook.
import React from 'react';
import './App.css';
function App() {
const [userInput, setUserInput] = useState(0);
inputchangehandler = (event) => {
setUserInput(event.target.value)
}
return (
<div className="App">
<input type="text" name="name"
onChange={this.inputchangehandler}
value = {userInput}/>
</div>
);
}
export default App;
Refer: https://reactjs.org/docs/hooks-state.html
If you are using an older version then you will need to convert it to a React.Component
If you don't want to write a class component, you should use hooks, so your code will be like this:
import React, { useState } from 'react';
import './App.css';
function App() {
const [userInput, setUserInput] = useState(undefined);
inputchangehandler = (event) => {
setUserInput(event.target.value)
}
return (
<div className="App">
<input type="text" name="name"
onChange={this.inputchangehandler}
value = {userInput}/>
</div>
);
}
export default App;
i was on React version 17 this worked for me for state undefined error:
Adding example from React official docs:
class Clock extends React.Component { constructor(props) {
super(props);
this.state = {date: new Date()}; }
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
); } }
Assuming you're working with a class component rather than a functional component (as mentioned in other answers), the error state is not defined can occur if you forgot to prefix it with this..
Instead of:
myFunction() {
let myVariable = state.myStateKey;
// ...
}
Do:
myFunction() {
let myVariable = this.state.myStateKey;
// ...
}

React Redux cant get reducer to pick up actions

I've been learning redux & react and am building a todo list. I've been reading and looking at different articles but cant figure out what I'm missing in my setup.
Currently you can add a todo via the input. On pushing enter it sends a addTodo action with the todo text.
I'm expecting the reducer to see the action type and update the state but it never does. What am I missing?
index.jsx
import React from 'react';
import ReactDOM from 'react-dom';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import reducer from './reducer.js';
import TodoList from './containers/container.js';
const store = createStore(reducer);
ReactDOM.render(
<Provider store={store}>
<TodoList />
</Provider>,
document.getElementById('app'));
actions.js
var uuid = require('node-uuid');
export function addTodo(text) {
console.log('action addTodo', text);
return {
type: 'ADD_TODO',
payload: {
id: uuid.v4(),
text: text
}
};
}
TodoListComponent.jsx
import React from 'react';
import TodoComponent from './TodoComponent.jsx';
import { addTodo } from '../actions/actions.js'
export default class TodoList extends React.Component {
render () {
const { todos } = this.props;
return (
<div>
<input type='text' placeholder='Add todo' onKeyDown={this.onSubmit} />
<ul>
{todos.map(c => (
<li key={t.id}>
<TodoComponent todo={t} styleName='large' />
</li>
))}
</ul>
</div>
)
}
onSubmit(e) {
const input = e.target;
const text = input.value;
const isEnterKey = (e.which === 13);
if (isEnterKey) {
input.value = '';
addTodo(text);
}
}
}
TodoComponent.jsx
import React from 'react';
import CSSModules from 'react-css-modules';
import styles from './style.css';
export default class TodoComponent extends React.Component {
render () {
const { todo } = this.props;
return (
<div styleName='large'>{todo.text}</div>
)
}
}
export default CSSModules(TodoComponent, styles);
container.js
import { connect } from 'react-redux';
import TodoList from '../components/TodoListComponent.jsx';
import { addTodo } from '../actions/actions.js';
const mapStateToProps = (state) => {
return {
todos: state
}
};
const mapDispatchToProps = (dispatch) => {
return {
addTodo: text => dispatch(addTodo(text))
}
};
export default connect(mapStateToProps, mapDispatchToProps)(TodoList);
reducer.js
import { List, Map } from 'immutable';
const init = List([]);
export default function(todos = init, action) {
console.log('reducer action type', action.type);
switch(action.type) {
case 'ADD_TODO':
console.log('ADD_TODO');
return todos.push(Map(action.payload));
default:
return todos;
}
}
In your TodoListComponent you are importing your actions directly from your actions file, but in fact you want to use the action that you map to dispatch and pass as property in the container. That explains why you see logs from the actions, but not from reducer, as the action is never dispatched to the store.
So your TodoListComponent should be:
import React from 'react';
import TodoComponent from './TodoComponent.jsx';
export default class TodoList extends React.Component {
render () {
const { todos } = this.props;
return (
<div>
<input type='text' placeholder='Add todo' onKeyDown={this.onSubmit} />
<ul>
{todos.map(c => (
<li key={t.id}>
<TodoComponent todo={t} styleName='large' />
</li>
))}
</ul>
</div>
)
}
onSubmit(e) {
const input = e.target;
const text = input.value;
const isEnterKey = (e.which === 13);
if (isEnterKey) {
input.value = '';
this.props.addTodo(text);
}
}
}
import React from 'react';
import TodoComponent from './TodoComponent.jsx';
export default class TodoList extends React.Component {
render () {
const { todos } = this.props;
return (
<div>
<input type='text' placeholder='Add todo' onKeyDown={this.onSubmit.bind(this)} />
<ul>
{todos.map(c => (
<li key={t.id}>
<TodoComponent todo={t} styleName='large' />
</li>
))}
</ul>
</div>
)
}
onSubmit(e) {
// use the addTodo passed via connect
const { addTodo } = this.props;
const input = e.target;
const text = input.value;
const isEnterKey = (e.which === 13);
if (isEnterKey) {
input.value = '';
addTodo(text);
}
}
}

Categories