I'm learning react + firebase. I also read about React server rendering & I want to test & see what is look like to have server rendering my app. so I use ReactDOMServer to render my component and can render my very simple component but I gotta problem when I try a component that uses rebase package for sync data between my app and Firebase. this is what warning I got:
Warning: setState(...): Can only update a mounting component. This
usually means you called setState() outside componentWillMount() on
the server. This is a no-op. Please check the code for the App
component.
here is my code:
App Component:
import React from 'react';
import Header from './Header';
import Orders from './Orders';
import Inventory from './Inventory';
import SampleFishes from '../sample-fishes';
import Fish from './Fish';
import base from '../base';
class App extends React.Component{
constructor(){
super();
this.addFish = this.addFish.bind(this);
this.loadSampleFishes = this.loadSampleFishes.bind(this);
this.addToOrder = this.addToOrder.bind(this);
this.liveUpdateFish = this.liveUpdateFish.bind(this);
this.removeFish = this.removeFish.bind(this);
this.removeOrder = this.removeOrder.bind(this);
this.state={
fishes:{},
orders:{}
};
}
componentWillMount(){
let prevOrder = localStorage.getItem(`${this.props.params.store}-order`);
this.ref = base.syncState(`${this.props.params.store}/fishes`,{
context:this,
state:`fishes`,
then(){
if(prevOrder){
this.setState({orders: JSON.parse(prevOrder)});
}
}
});
}
componentWillUnmount(){
base.removeBinding(this.ref);
}
componentWillUpdate(nextProps,nextState){
localStorage.setItem(`${this.props.params.store}-order`,JSON.stringify(nextState.orders));
}
loadSampleFishes(){
let fishes = {...this.state.fishes,...SampleFishes};
this.setState({fishes});
}
addFish(fish){
let fishes = {...this.state.fishes};
fishes[`fish-${Date.now()}`]= fish;
this.setState({fishes});
}
addToOrder(key){
let orders = {...this.state.orders};
orders[key] = orders[key]+1 ||1;
this.setState({orders});
}
liveUpdateFish(fish,k){
let fishes = {...this.state.fishes};
fishes[k] = fish;
this.setState({fishes});
}
removeFish(key){
let fishes = {...this.state.fishes};
fishes[key] = null;
this.setState({fishes});
this.removeOrder(key);
}
removeOrder(key){
let orders = {...this.state.orders};
delete orders[key];
this.setState({orders});
}
render(){
return (
<div className="catch-of-the-day">
<div className="menu">
<Header tagline="Fresh SeaFood Market"/>
<ul>
{
Object.keys(this.state.fishes).map(key=><Fish addToOrder={this.addToOrder} id={key} key={key} fish={this.state.fishes[key]} />)
}
</ul>
</div>
<Orders orders={this.state.orders} fishes={this.state.fishes} removeOrder={this.removeOrder}/>
<Inventory addFish={this.addFish} loadSampleFishes={this.loadSampleFishes} fishes={this.state.fishes} liveUpdate={this.liveUpdateFish} removeFish={this.removeFish} />
</div>
);
}
}
export default App;
Orders Component:
import React from 'react';
import Order from './Order';
import {formatPrice} from '../helpers';
class Orders extends React.Component{
render(){
const orderIDs = Object.keys(this.props.orders);
let list = null;
if(orderIDs.length===0){
list = <li>OOPS there is no item</li>;
}else{
list = Object.keys(this.props.orders).map(key=><Order removeOrder={this.props.removeOrder} fish={this.props.fishes[key]} key={key} index={key} order={this.props.orders[key]}/>)
}
const total = orderIDs.reduce((prev,index)=>{
if(!this.props.fishes[index]) return prev;
if(!this.props.fishes[index].price) return prev;
return prev+this.props.fishes[index].price*this.props.orders[index]},0);
return (
<div className="order-wrap">
<h2>Your Orders</h2>
<ul className="order">
{list}
<li className="total">total is {formatPrice(total)}</li>
</ul>
</div>
);
}
}
export default Orders;
Order Component:
import React from 'react';
import {formatPrice} from '../helpers';
class Order extends React.Component{
render(){
const removeButton = <button onClick={e=>this.props.removeOrder(this.props.index)}>❌</button>
return (
<li><span>{this.props.order}x {this.props.fish.name}</span><span className="price">{formatPrice(this.props.fish.price)}</span>{removeButton}</li>
);
}
}
export default Order;
Inventory Component:
import React from 'react';
import AddFishForm from './AddFishForm'
class Inventory extends React.Component{
constructor(props){
super(props);
this.returnInventory = this.returnInventory.bind(this);
this.handleChanges = this.handleChanges.bind(this);
}
handleChanges(e,key){
const fish = this.props.fishes[key];
const updatedFish = {...fish,
[e.target.name] : e.target.value
};
this.props.liveUpdate(updatedFish,key);
}
returnInventory(key){
const fish = this.props.fishes[key];
return(
<div className="fish-edit" key={key}>
<input name="name" value={fish['name']} type="text" placeholder="fish name" onChange={e=>this.handleChanges(e,key)} />
<input name="price" value={fish['price']} type="text" placeholder="fish price" onChange={e=>this.handleChanges(e,key)} />
<select name="status" value={fish['status']} onChange={e=>this.handleChanges(e,key)}>
<option value="available">Fresh!</option>
<option value="unavailable">Sold Out!</option>
</select>
<textarea name="desc" value={fish['desc']} type="text" placeholder="fish desc" onChange={e=>this.handleChanges(e,key)}></textarea>
<input name="image" value={fish['image']} type="text" placeholder="fish image" onChange={e=>this.handleChanges(e,key)} />
<button onClick={e=>this.props.removeFish(key)}>- Remove Fish</button>
</div>
)
}
render(){
return (
<div>
<h2>Inventory</h2>
{
Object.keys(this.props.fishes).map(key=>this.returnInventory(key))
}
<AddFishForm addFish={this.props.addFish}/>
<button onClick={this.props.loadSampleFishes}>Load Sample Fishes</button>
</div>
);
}
}
export default Inventory;
Fish Component:
import React from 'react';
import {formatPrice} from '../helpers';
class Fish extends React.Component{
addOrder(k){
console.log(k);
this.props.addToOrder(k);
}
render(){
let available = this.props.fish.status ==='available';
let buttonText = available?'Order it':'Sold Out';
return (<li className="menu-fish" id={this.props.id}>
<img src={this.props.fish.image} alt={this.props.fish.name}/>
<h3 className="fish-name">{this.props.fish.name}<span className="price">{formatPrice(this.props.fish.price)}</span>
</h3>
<p className="fish-desc">{this.props.fish.desc}</p>
<button disabled={!available} onClick={(e)=>this.addOrder(this.props.id)}>{buttonText}</button>
</li>);
}
}
export default Fish;
Related
i'm getting the following error while trying to search. I'm using redux to hold my state. Everytime i navigate away from the following page and back to it i get the error.
"Uncaught TypeError: Cannot read properties of undefined (reading 'toLowerCase')"
the following is my insurance component
import React, { Component } from 'react';
import { connect } from "react-redux";
import { fetchAllInsurances } from '../../actions/insurance.action';
import { Link } from 'react-router-dom';
import Card from '../Card';
import SearchBar from '../SearchBar';
import Header from '../Header';
export class Insurance extends Component {
constructor(props){
super(props);
this.state = {sCode:null};
}
onSearchSubmit = (term) => {
this.setState({sCode:term})
}
componentDidMount(){
this.props.fetchAllInsurances();
}
render() {
return (
<>
<Header/>
<div>
<SearchBar onSubmit={this.onSearchSubmit}/>
</div>
<br></br>
{this.renderCreate()}
<br></br>
<br></br>
<br></br>
{this.renderCard()}
</>
)
}
renderCreate(){
return(
<>
<Link to ={'/addinsurance'} className = "ui primary button">Add Insurance</Link>
</>
)
}
renderCard(){
return(
<div className="ui four column grid">
{this.props.insurance.filter(((c)=>{
if(this.state.sCode == null){
return c;
}
else if(c.VendorName.toLowerCase().includes(this.state.sCode.toLowerCase().toString())){
return c
}
})).map((c, i) => (
<Card key={i} InsData={c} />
))}
</div>
)
}
}
const mapStateToProps = state =>{
return{
insurance:Object.values(state.insurance)
}
}
export default connect(mapStateToProps,{fetchAllInsurances})(Insurance);
the following is my search component
import React from 'react'
class SearchBar extends React.Component {
state = {term:''};
onFormSubmit =(event) =>{
event.preventDefault();
//send the state data to the parent
this.props.onSubmit(this.state.term);
}
render(){
return (
<div className='ui segment'>
<form onSubmit = {this.onFormSubmit} action="" className="ui form">
<div className="field">
<label>Insurance Vendor Search</label>
<div className="searchInputs">
<input
type="text"
value={this.state.term}
onChange={e=> this.setState({term:e.target.value})}
placeholder='Enter the insurance vendor to search...'/>
</div>
</div>
</form>
</div>
)
}
}
export default SearchBar;
As the error state, the variable is undefined. You will need to test the variable first.
So either use
c.VendorName?.toLowerCase()
or
if (c.VendorName) {
c.VendorName.toLowerCase()........
}
I am writing a react application that outputs a list of books (image, title, category, and description).
My search bar and booklist are sibling components and the search bar will pass data to the booklist.
when clicking the search button, only "Sample Category" shows up but not anything else. There is no problem accessing the API and the data is not null.
Here is a sample API output: https://www.googleapis.com/books/v1/volumes?q=lordoftherings
My code is the following:
// App
import React, { Component } from 'react';
import Axios from 'axios';
import './App.css';
import SearchBar from './SearchBar';
import BookList from './BookList';
class App extends Component {
constructor(props) {
super(props);
this.state = {
books: []
};
this.search = this.search.bind(this);
}
search(title) {
const promise = Axios.get('https://www.googleapis.com/books/v1/volumes?q=' + title);
promise.then((response) => {
const books = response.data.items;
this.setState({ books: books });
console.log(this.state.books);
})
};
render() {
return (
<div className="App">
<SearchBar searchBooks = {this.search}/>
<BookList booklist = {this.state.books}/>
</div>
);
}
}
export default App;
// Search Bar
import React, { Component } from 'react';
import PropTypes from 'prop-types';
class SearchBar extends Component {
constructor(props) {
super(props);
this.state = { titleToSearch: 'harry potter' }
this.handleInputChange = this.handleInputChange.bind(this);
}
handleInputChange(e) {
this.setState({ titleToSearch: e.target.value });
};
render() {
return (
<form>
<input
type="text"
name="booksInput"
placeholder="Enter book title"
value={this.state.titleToSearch}
onChange={this.handleInputChange}
/>
<button type="button" onClick={() => this.props.searchBooks(this.state.titleToSearch)}>Search</button>
</form>
);
}
}
export default SearchBar;
// BookList
import React, { Component } from 'react';
class BookList extends Component {
render() {
const books = this.props.booklist;
return (
<div className="table">
{books.map((book) => {
console.log(book.id);
return (
<div className="box" key={book.id}>
<div className="img"><img src="assets/default-placeholder.jpg" alt="" /></div>
<div className="title">{book.title}</div>
<div className="category">Sample Category</div>
<div className="description">{book.description}</div>
</div>
);
})}
</div>
);
}
}
export default BookList;
In the sample code you provided, you're not actually dynamically outputting categories.
You've hard coded 'Sample category' in there.
book.category
...is not actually in the dataset.
There are categories which seem to be available under:
<div className="category">{book.volumeInfo.categories[0]}</div>
although you'll want to check if the array has length, and probably map or join each item in array to string.
just to be clear: the issue with your other fields is also that they're children of "volumeInfo"
I need some help building a todo list with React. Im a beginner so there are a lot of aspects of react I don't understand. I've created a Todo list at the moment this lists an un ordered list with the input, edit and remove button a select menu and a further input field.
Firstly Im confused to where I update my state. the "App.js" is where my main state is stored and im trying to keep it that way. I need to know how to edit the input field (todo listitem) which stores the new value. Im then looking to create a "completed list" where i want to store the input field as well as the select option (which ever is clicked) Please could someone give me some guidelines for this. Thank you in advance
import React, { Component } from 'react';
import Form from './Components/Form'
import './App.css';
import List from './Components/List'
import Completed from './Components/Completed'
class App extends Component {
constructor(props){
super(props)
this.state={
isEditing:false,
text:"",
items:[],
completed:[
{
}
]
}
this.submit=this.submit.bind(this);
this.eventHandler=this.eventHandler.bind(this)
}
submit=(e)=>{
e.preventDefault();
this.setState({
items:[
{
name:this.state.text,
},
...this.state.items
],
text:""
})
}
remove=(index)=>{
this.setState({
items:this.state.items.filter((_,i) => i!==index)
})
}
onChange=(index)=>{
this.setState({
items:this.state.items.filter((_,i) => i!==index)
});
}
eventHandler=(e)=>{
this.setState ({
text:e.target.value
})
}
handleNameEdits=()=>{
this.setState({
isEditing:true
})
}
edit=()=>{
this.setState({
isEditing:!this.state.isEditing
})
}
myoptions=(e)=>{
this.setState({
completed:[
{
webmaster:e
},
...this.state.completed
]
})
}
render() {
return (
<div className="App">
<header className="App-header">
<Form submit={this.submit} myValue={this.state.text} eventHandler=
{this.eventHandler}/>
{this.state.items.map && this.state.items.map((item,index)=>(
<List key={index}
name={item.name}
edit={this.edit}
change={()=>this.onChange(index)}
remove={()=>this.remove(index) }
handleNameEdits={this.handleNameEdits}
myoptions={(e =>this.myoptions(e.target.value))}
/>
))}
</header>
<div>
completed
</div>
</div>
);
}
}
export default App;
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import Edit from './Edit';
class List extends Component {
constructor(props) {
super()
this.options = [
{name:'web1'},
{name:'web2'},
{name:'web3'},
{name:'web4'}
];
}
render() {
const {key} = this.props;
const x=this.options;
return (
<ul>
<li>{this.props.name}
<button onClick={this.props.edit}>Edit</button>
<button onClick={this.props.remove}>Remove</button>
<select onChange={this.props.myoptions}>
{this.options.map(options => <option>{options.name}</option> )}
</select>
<label> Completed
</label><input type="checkbox" onChange=
{this.props.change} checked={this.props.change} onClick=
{this.props.submit}/>
<label> Ticket Number </label><input type='text'/>
</li>
</ul>
)
}
}
export default List;
import React from 'react'
import PropTypes from 'prop-types';
const Form= props=> {
return (
<form onSubmit={props.submit}>
<input type='text' value={props.myValue} onChange=
{props.eventHandler}/>
<button> click</button>
</form>
)
}
Form.PropTypes={
onSubmit:PropTypes.func.isRequired,
evenHandler:PropTypes.func.isRequired,
myValue:PropTypes.string.isRequired
}
export default Form
I'm new to ReactJs, coding and this is my first time posting here! So, I'm trying to build a Todo app in ReactJs. I have four components.
the first compo. is App.js - the parent one
import React, { Component } from 'react';
import TaskTodo from './TaskTodo';
import './App.css';
import TaskDisplayed from "./TaskDisplayed";
class App extends Component {
render() {
return (
<div className="App">
<header className="App-header">
<h1 className="App-title">Hey, i'm the header! </h1>
</header>
<div className="App-intro">
<TaskTodo/>
</div>
<div className="App-right">
<TaskDisplayed/>
</div>
</div>
);
}
}
export default App;
TaskTodo.js - which is the parent of the TodoItems.js
import React, {Component} from 'react';
import TodoItems from './TodoItems';
export default class TaskTodo extends Component{
constructor(props) {
super(props);
this.state = {
items: []
};
this.addItem = this.addItem.bind(this);
};
addItem(e) {
const itemArray = this.state.items;
if (this._inputElement.value !== "") {
itemArray.unshift(
{
text: this._inputElement.value,
key: Date.now()
}
);
this.setState({
items: itemArray
});
this._inputElement.value = "";
}
e.preventDefault();
}
render() {
return (
<div className="todoListMain">
<div className="header">
<form onSubmit={this.addItem}>
<input type="text" ref={(a) => this._inputElement = a}
placeholder="Add a list">
</input>
</form>
</div>
<TodoItems entries={this.state.items}/>
</div>
);
}
}
TodoItems.js - the child of the TaskTodo.js
import React, { Component } from 'react';
class TodoItems extends Component {
constructor(props) {
super(props);
this.createTasks = this.createTasks.bind(this);
}
handleClick = (text) => {
console.log(text);
}
createTasks(item) {
return <li key={item.key}><a onClick={() => this.handleClick(item.key, item.text)} href={'#about'}>#{item.text}</a></li>
}
render() {
const todoEntries = this.props.entries;
const listItems = todoEntries.map(this.createTasks);
return (
<ul className="theList">
{listItems}
</ul>
);
}
};
export default TodoItems;
What I need to do, is how I can pass the handleClick method (a child's of TaskTodo) to an 'external' component - TaskDisplayed.js; or how I can track when the user click to a listed item? Please pardon me for this unprofessional way of asking! But, I truly need to get in track with ReactJS! Thanks!
p.s. The above code I found online, so thanks for that :D!
You should define the onClick event handler in the parent component and pass it to the child as a prop.
See How to pass an event handler to a child component in React
In this case, you would want to define it in the App component since that is the parent of the two components that need to communicate.
when trying to click the delete button the error is displayed stating that cannot read props of null and try to bind the method in the constructor class using bind.this but again the same error is displayed. also bind the value at the bottom of the component again the same error that cannot read value of props as null
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import SampleData from './data.js';
import _ from 'lodash';
import AppList from './Applist';
import Appointment from './Appointment';
import './App.css';
class App extends Component {
constructor(){
super()
this.state = {
data:[],
aptBodyVisible: false
}
this.deleteMessage = this.deleteMessage.bind(this);
this.toggleAddDisplay = this.toggleAddDisplay.bind(this);
}
componentDidMount(){
this.setState({data: SampleData})
}
deleteMessage(item) {
var allApts = this.state.data;
var newApts = _.without(allApts, item);
this.setState({
data: newApts
});
}
toggleAddDisplay(){
var tempVisibility = !this.state.aptBodyVisible;
this.setState({
aptBodyVisible: tempVisibility
})
}
render() {
var filtered = this.state.data;
filtered = filtered.map((item, index)=>{
return(
<AppList key = { index }
singleItem = { item }
whichItem = { item }
onDelete = {this.deleteMessage}
/>
)
})
return (
<div className="main">
<Appointment
bodyVisible = { this.state.aptBodyVisible }
handleToggle = { this.toggleAddDisplay } />
<ul className="item-list media-list">{filtered} </ul>
</div>
);
}
}
export default App;
child class component
import React, { Component } from 'react';
class AppList extends Component {
handleDelete(){
this.props.onDelete(this.props.whichItem);
}
render(){
return(
<li className="pet-item media">
<div className="media-left">
<button className="pet-delete btn btn-xs btn-danger"
onClick = {this.handleDelete}>
<span className="glyphicon glyphicon-remove"></span></button>
</div>
<div className="pet-head">
<span className="pet-name">{this.props.singleItem.petName}</span>
<span className="apt-date pull-right">{this.props.singleItem.aptDate}</span>
</div>
<div className="owner-name"><span className="label-item">Owner:</span>
{this.props.singleItem.ownerName}</div>
<div className="apt-notes">{this.props.singleItem.aptNotes}</div>
</li>
)
}
}
export default AppList;
From the React Documentation
The constructor for a React component is called before it is mounted. When implementing the constructor for a React.Component subclass, you should call super(props) before any other statement. Otherwise, this.props will be undefined in the constructor, which can lead to bugs.
Like this:
constructor(props){
super(props);
this.state = {
data:[],
aptBodyVisible: false
}
this.deleteMessage = this.deleteMessage.bind(this);
this.toggleAddDisplay = this.toggleAddDisplay.bind(this);
}
yes again we need to bind the method in the child components even to work with the click events
onClick = {this.handleDelete.bind(this)}