React Props for Handle Change not a Function - javascript

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}
...
/>
}

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

React function component not rendering an app component

I'm a newbie to React. My array of messages is not rendering. I've verified that my array, which is part of the Messages state, is getting made properly, so I'm really confused as to why this is happening. Do I need to make all the components functional components?
ChatApp.js uses Messages.js which is a list that is generated from Message.js
ChatApp.js
import React, {useState} from 'react';
import config from '../config';
import Messages from './Messages';
import ChatInput from './ChatInput';
import Container from 'react-bootstrap/Container';
import Image from 'react-bootstrap/Image';
import Card from 'react-bootstrap/Card';
import Row from 'react-bootstrap/Row';
import Col from 'react-bootstrap/Col';
import Button from 'react-bootstrap/Button';
import Media from 'react-bootstrap/Media';
import {useParams} from 'react-router-dom';
import {useSelector} from 'react-redux';
import { connect } from 'react-redux';
require('../styles/ChatApp.css');
const ChatApp = () => {
const [messages, setMessages] = React.useState([]);
const userId = useSelector(state => state.profile.profile._id);
const role = useSelector(state => state.profile.profile.role);
const addMessage = (message) => {
const messagess = [...messages];
messagess.push(message);
setMessages(messagess);
console.log(messagess);
}
const sendHandler = (message) => {
const messageObject = {
username: userId,
message
};
addMessage(messageObject);
}
return (
<div className="landing">
<Container>
<Row className="mt-5">
<Col md={{ span: 8, offset: 2 }}>
<Card style={{ height: "36rem" }} border="dark">
<Messages msgs={messages} />
<Card.Footer>
<ChatInput onSend={sendHandler}>
</ChatInput>
</Card.Footer>
</Card>
</Col>
</Row>
</Container>
</div>
)
};
ChatApp.defaultProps = {
username: 'anonymous'
};
const mapStateToProps = (state) => {
return {
authUser: state.auth.user,
profile: state.profile.profile
};
};
export default connect(
mapStateToProps
)(ChatApp);
Messages.js
import React from 'react';
import Message from './Message';
class Messages extends React.Component {
componentDidUpdate() {
// There is a new message in the state, scroll to bottom of list
const objDiv = document.getElementById('messageList');
objDiv.scrollTop = objDiv.scrollHeight;
}
render() {
// Loop through all the messages in the state and create a Message component
const messages = this.props.messages.map((message, i) => {
return (
<Message
key={i}
username={message.username}
message={message.message}
fromMe={message.fromMe} />
);
});
return (
<div className='messages' id='messageList'>
{ messages }
</div>
);
}
}
Messages.defaultProps = {
messages: []
};
export default Messages;
Message.js
import React from 'react';
import Image from 'react-bootstrap/Image'
import Media from 'react-bootstrap/Media';
class Message extends React.Component {
render() {
return (
<ul className="list-unstyled">
<Media as="li">
<Media.Body>
<h6 className="font-weight-bold">{ this.props.username }</h6>
<p>
{ this.props.message }
</p>
<p className="small text-muted">
3 hrs ago
</p>
</Media.Body>
</Media>
</ul>
);
}
}
Message.defaultProps = {
message: '',
username: '',
to: '',
fromMe: false
};
export default Message;

Changing the image source in a react component

I am getting an error, 'Attempted to assign to readonly property'. I am not sure how to decipher this error message and I feel like my logic looks ok. I am not quite sure where to look.
container component:
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import { Image } from './Image.js'
import { Button } from './Button.js'
const images = ['https://uploads3.wikiart.org/images/wladyslaw-strzeminski/cover-for-a-book-by-julian-przybo-z-ponad-1930.jpg!Large.jpg',
'https://uploads6.wikiart.org/images/pablo-picasso/girl-on-the-ball-1905.jpg!Large.jpg',
'https://uploads8.wikiart.org/images/salvador-dali/et-post-buccellam-introivit-in-eum-satanas-psalms-40-10-1964.jpg']
class Game extends React.Component{
constructor(props){
super(props)
this.state = {
currentImg: 0
}
this.handleClick = this.handleClick.bind(this)
}
handleClick(){
const current = this.state.currentImg; <--------- error points to this
const next = ++current % images.length;
this.setState({
currentImg: next
})
}
render(){
let src = this.state.currentImg;
return(
<div>
<Image src={images[src]} />
<Button onClick={this.handleClick} />
</div>
)
}
}
ReactDOM.render(
<Game />,
document.getElementById('root')
);
presentational components:
Button:
import React from 'react';
export const Button = (props) => {
return <button onClick={props.onClick}></button>
}
Image:
import React from 'react';
export const Image = (props) => {
return (
<div className="flex-main-item">
<img className="mainImage" src={props.src} />
</div>
)
}

onchange input and set state not working?

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
}

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