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>
)
}
Related
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
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}
...
/>
}
I'm currently working on creating a PokeDex by using the PokeApi. I'm trying to complete the PokemonList, that will contain all the different PokemonCard buttons.
I am receiving expected ";" error for my componentDidMount and I'm unsure why.
The code for the page is
import React from "react";
import PokemonCard from "./PokemonCard";
import "../ui/PokemonList.css";
import axios from 'axios';
export default class PokemonList extends Component {
state = {
url: "https://pokeapi.co.api.v2.pokemon/",
pokemon: null
};
}
componentDidMount() {
const res = axios.get(this.state.url);
this.setState({pokemon: res.data['results'] });
}
const PokeList = () => {
return (
<section className="poke-list">
<PokemonCard />
<PokemonCard />
<PokemonCard />
<PokemonCard />
<PokemonCard />
<PokemonCard />
<PokemonCard />
<PokemonCard />
<PokemonCard />
</section>
);
};
//export default PokeList;
It is marking the error on the { symbol after componentDidMount().
The error remains there, even after I add a semi-colon after the curly brackets, even though I don't think the semi-colon is necessary, since the guide I'm following doesn't do it.
Is there some simple rule that I'm breaking? I'm new to React / JavaScript.
edit ----------------------------------------------------
My Dashboard.Js code is
import React, { Component } from "react";
import PokeList from "../pokemon/PokemonList";
export default class Dashboard extends Component {
render() {
return (
<div>
<div className="row">
<div className="col">
<PokeList />
</div>
</div>
</div>
);
}
}
I am getting the following error now
./src/components/layout/Dashboard.js
Attempted import error: '../pokemon/PokemonList' does not contain a default export (imported as 'PokeList').
probably because
import React from "react";
import PokemonCard from "./PokemonCard";
import "../ui/PokemonList.css";
import axios from 'axios';
export default class PokemonList extends Component {
state = {
url: "https://pokeapi.co.api.v2.pokemon/",
pokemon: null
};
} <----- extra curly brace remove this
componentDidMount() {
const res = axios.get(this.state.url);
this.setState({pokemon: res.data['results'] });
}
//keep this function inside class
PokeList = () => {
return (
<section className="poke-list">
<PokemonCard />
<PokemonCard />
<PokemonCard />
<PokemonCard />
<PokemonCard />
<PokemonCard />
<PokemonCard />
<PokemonCard />
<PokemonCard />
</section>
);
};
render() {
return(
<div>{this.Pokelist}</div>
)
}}
//export default PokeList; // <=== remove this
Your component did mount was outside the class component.
to make your current code work --
import React from "react";
import PokemonCard from "./PokemonCard";
import "../ui/PokemonList.css";
import axios from 'axios';
export const PokemonList = class PokemonList extends Component {
state = {
url: "https://pokeapi.co.api.v2.pokemon/",
pokemon: null
};
componentDidMount() {
const res = axios.get(this.state.url);
this.setState({pokemon: res.data['results'] });
}
} <==== class component ended
export const PokeList = () => {
return (
<section className="poke-list">
<PokemonCard />
<PokemonCard />
<PokemonCard />
<PokemonCard />
<PokemonCard />
<PokemonCard />
<PokemonCard />
<PokemonCard />
<PokemonCard />
</section>
);
};
Dashboard js
import React, { Component } from "react";
import {PokeList} from "../pokemon/PokemonList";
export default class Dashboard extends Component {
render() {
return (
<div>
<div className="row">
<div className="col">
<PokeList />
</div>
</div>
</div>
);
}
}
The first issue is invalid url.
Change url with: https://pokeapi.co/api/v2/pokemon/
See code example:
import React, { Component } from "react";
import ReactDOM from "react-dom";
import PokemonList from "./components/PokemonList";
import "./styles.css";
class App extends Component {
render() {
return (
<div className="App">
<PokemonList />
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
import React, { Component } from "react";
import axios from "axios";
import PokemonCard from "./PokemonCard";
class PokemonList extends Component {
constructor(props) {
super(props);
this.state = {
url: "https://pokeapi.co.api.v2.pokemon/",
pokemons: []
};
}
componentDidMount = () => {
axios
.get("https://pokeapi.co/api/v2/pokemon/")
.then(response => {
const data = response.data.results;
this.setState({ pokemons: data });
})
.catch(error => {
console.log(error);
});
};
render() {
const { pokemons } = this.state;
return (
<div className="pokemon-list">
{pokemons.length > 0 &&
pokemons.map(pokemon => {
return <PokemonCard pokemon={pokemon} />;
})}
</div>
);
}
}
export default PokemonList;
import React, { Component } from "react";
class PokemonCard extends Component {
render() {
const { pokemon } = this.props;
console.log(pokemon);
return (
<div className="pokemon-card">
<p>Name: {pokemon.name}</p>
<p>
Url: <a href={pokemon.url}>{pokemon.url}</a>
</p>
</div>
);
}
}
export default PokemonCard;
I have a styled class component below, it define a TextInput and with Icon and placeholder two props.
import React, { Component } from "react";
import { View, Text, TextInput } from "react-native";
import styled from "styled-components/native";
const StyledView = styled.View`
...
`;
const StyledIconView = styled.View`
...
`;
const StyledTextInput = styled.TextInput`
...
`;
class LoginTextInput extends React.Component {
constructor(props) {
super(props);
this.state = { text: this.props.text };
}
render() {
const { Icon } = this.props; // it seems have a problem here
return (
<StyledView>
<StyledIconView>
<Icon /> // and here
</StyledIconView>
<StyledTextInput
placeholder={this.state.text}
onChangeText={searchString => {
this.setState({ searchString });
}}
/>
</StyledView>
);
}
}
export default LoginTextInput;
And then I can use this component to customize my own case.
import React from "react";
import { View, Text, StyleSheet, TextInput } from "react-native";
import LoginTextInput from "./LoginTextInput";
import Icon from "react-native-vector-icons/FontAwesome";
import SimpleIcon from "react-native-vector-icons/SimpleLineIcons";
const UserIcon = () => <Icon name="user-o" size={20} color="#757575" />;
class Login extends React.Component {
constructor(props) {
super(props);
this.state = { text: "Useless Placeholder" };
}
render() {
return (
<View>
/* <LoginTextInput text="input use name" Icon={UserIcon} /> */
<LoginTextInput text="input use name" Icon={<UserIcon />} />
</View>
);
}
}
export default Login;
But this code can not be compiled and report a "expect a string or a class/function, but get: undefined" error.
I tag the error above, it seems the Icon props can not be defined in this code.
SOLUTION
Because I use the component UserIcon, so it should be let it changed to <UserIcon / >.
I am building a react app that deals with budgeting and I have written the code for a BillContainer component and an AddBill component.
This is my code:
BillContainer.js
import React from 'react';
import BillList from './BillList';
import AddBill from './AddBill';
class BillContainer extends React.Component {
constructor(props) {
super(props)
this.state = {
bills: [
]
}
this.addBill = this.addBill.bind(this)
}
addBill(bill) {
this.setState((state) => ({
bills: state.bills.concat([bill])
}));
}
render() {
return (
<div>
<AddBill addNew={this.addBill} />
<BillList bills={this.state.bills} />
</div>
)
}
}
export default BillContainer;
and AddBill.js
import React from 'react';
class AddBill extends React.Component {
constructor(props) {
super(props)
this.state = {
newBill: ''
};
this.updateNewBill = this.updateNewBill.bind(this)
this.handleAddNew = this.handleAddNew.bind(this)
}
updateNewBill(e) {
this.setState({
newBill: e.target.value
})
}
handleAddNew(bill) {
this.props.addNew(this.state.newBill)
this.setState({
newBill: ''
})
}
render() {
return (
<div>
<input
type='text'
value={this.state.newBill}
onChange={this.updateNewBill}
/>
<button onClick={this.handleAddNew}> Add Bill </button>
</div>
)
}
}
export default AddBill;
and this is my AddBill.test.js test:
import React from 'react';
import ReactDOM from 'react-dom';
import Enzyme from 'enzyme';
import { shallow, mount, render } from 'enzyme';
import EnzymeAdapter from 'enzyme-adapter-react-16';
import AddBill from '../components/AddBill';
let Sinon = require('sinon')
Enzyme.configure({adapter: new EnzymeAdapter() });
it('Adds a bill to the list', () => {
const clickSpy = Sinon.spy(AddBill.prototype, 'handleAddNew');
const wrapper = shallow(
<AddBill />
);
wrapper.find('button').simulate('click');
expect(clickSpy.calledOnce).toEqual(true)
})
Im trying to test that a new bill gets added when the Add Bill button is clicked. I've passed the addBill function as a prop but the test is throwing the error TypeError: this.props.AddNew is not a function.
How do I prevent the error message and and make this.props.addNew() not undefined?
You can use jest.spyOn like so:
it('Adds a bill to the list', () => {
const wrapper = shallow(
<AddBill addNew={() => {}} />
);
const clickSpy = jest.spyOn(wrapper.instance(), 'handleAddNew');
wrapper.find('button').simulate('click');
expect(clickSpy).toHaveBeenCalledTimes(1);
})
You're not passing an addNew property:
const wrapper = shallow(
<AddBill addNew={yourAddNewFunction} />
);