Error saying rowRenderer is not a function - javascript

I'm trying to implement react-virtualized, so I went into official doc here, and completed it in my code , here is my code :
import React from "react";
import { List } from "react-virtualized";
class Users extends React.Component {
state = {
userList: ["1", "222", "33"]
};
rowRenderer({ key, index, isScrolling, isVisible, style }) {
return (
<div key={key} style={style}>
{
console.log(this.state.userList[index])
//this.state.userList[index]
}
</div>
);
}
render() {
return (
<div>
<List
width={300}
height={300}
rowCount={this.state.userList.length}
rowHeight={20}
rowRenderer={Users.rowRenderer}
/>
</div>
);
}
}
export default Users;
Now the thing is in rowRender function, it console.log perfectly. But when I replace that with the commented line, it gives me error saying rowRenderer is not a function and when I add function before that, it gets parsing error.
How this can be resolved?
codesandbox.io
In codesandbox it is giving one more error : A cross-origin error was thrown.

Users is your class definition, but the rowRenderer function is a method on your class instance. You should use this.rowRenderer instead.
import React from "react";
import { List } from "react-virtualized";
class Users extends React.Component {
state = {
userList: ["1", "222", "33"]
};
rowRenderer = ({ key, index, isScrolling, isVisible, style }) => {
return (
<div key={key} style={style}>
{this.state.userList[index]}
</div>
);
}
render() {
return (
<div>
<List
width={300}
height={300}
rowCount={this.state.userList.length}
rowHeight={20}
rowRenderer={this.rowRenderer}
/>
</div>
);
}
}
export default Users;

You can try writing rowRenderer function after render. With full code only i can test. Something like this:
import React from 'react';
import * as StaticData from '../StaticData'
import {List} from 'react-virtualized';
class Users extends React.Component{
state={
userList:['1','222','33']
};
componentDidMount() {
StaticData.getData("/users").then(data => {
this.setState({userList:data});
console.log(this.state.userList)
});
}
render() {
function rowRenderer({
key,
index,
isScrolling,
isVisible,
style,
}) {
return (
<div key={key} style={style}>
{
console.log(key)
//this.state.userList[index]
}
</div>
);
}
return(
<div>
<List
width={300}
height={300}
rowCount={this.state.userList.length}
rowHeight={20}
rowRenderer={Users.rowRenderer}
/>
</div>
);
}
}
export default Users;

Related

React Link To not updating the component

I am using React with Redux to list number of items and inside the item I have a list of similar items
In Home Page (there is a list of items when you click on any of them , it goes to the item path ) which is working well , but inside the item page , when you click on any items from similar items list (the view not updating )
the codeSandobx is here
App.js
const store = createStore(ItemsReducer, applyMiddleware(...middlewares));
class App extends React.Component {
render() {
return (
<Provider store={store}>
<Main />
</Provider>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
main.js
const Main = () => {
return (
<Router>
<div>
<Header />
<div className="container-fluid">
<Switch>
<Route exact path="/" component={Home} />
<Route path="/item/:id" component={Item} />
</Switch>
</div>
</div>
</Router>
);
};
export default Main;
Home.js
class Home extends React.Component {
render() {
const itemsList = this.props.items.map(item => {
return <ItemList item={item} key={item.id} />;
});
return <div className="items-list"> {itemsList}</div>;
}
}
const mapStateToProps = state => ({
items: state.items,
user: state.user
});
export default connect(mapStateToProps, null, null, {
pure: false
})(Home);
Item.js
class Item extends React.Component {
constructor(props) {
super();
this.state = {
item_id: props.match.params.id,
};
}
render() {
const itemsList = this.props.items.map(item => {
return <ItemList item={item} key={item.id} />;
});
return (
<div id="item-container">
<div className="item-list fav-items"> {itemsList} </div>;
</div>
);
}
}
const mapStateToProps = state => ({
items: state.items,
user: state.user
});
export default connect(mapStateToProps, null, null, {
pure: false
})(Item);
and finally the ItemList.js
class ItemList extends React.Component {
render() {
const item = this.props.item;
const item_link = "/item/" + item.id;
return (
<Link to={item_link}>
<div className="item-li">
{item.title}
</div>
</Link>
);
}
}
export default ItemList;
I've tired to use this solution from react-redux docs , but it didn't work
What do you expect to update on link click?
Any path /item/:id (with any id: 2423, 2435, 5465) will show the same result, because you don't use params.id inside the Item component
UPDATED
When id changes the component doesn't remount, only updates component (It's correct behavior)
If you want to fetchData on each changes of id, the next solution has to work for you
on hooks:
const Item = () => {
const params = useParams();
useEffect(() => {
axios.get(`/item/${params.id}`).then(...)
}, [params.id]);
return (
...
)
}
useEffect will call fetch each time when id is changing
and in class component you have to use componentDidUpdate:
class Item extends Component {
componentDidMount() {
this.fetchData();
}
componentDidUpdate(prevProps) {
if (prevProps.match.params.id !== this.props.match.params.id) {
this.fetchData();
}
}
fetchData = () => {
...
}
...
}

How can I use onClick on stateless component in React?

I want to use onClick on a stateless compoenent but it's reject an error like : onClick listener to be a function, instead got a value of object type.
I need to show and hide component on click.
Example when I click on the <ResultCard/> component I want to hide him and show <ResultDetail/>
State React Component :
import React, { Component } from "react";
import ResultCard from "./ResultCard";
import "../../assets/css/Result.css";
import Spinner from "../Spinner";
import { getApiToken, getParisByPrice } from "../../services/api";
import Modal from "../Modal";
import "../../assets/css/BudgetEntry.css";
import modify from "../../assets/images/modify.png";
import ResultDetail from "./ResultDetail";
class Results extends Component {
state = {
priceValue: "",
showResult: true
};
showResultDetail = () => {
this.setState({ showResult: false });
};
closeResultDetails = () => {
this.setState({ showResult: true });
};
render() {
return (
<div className="results-container">
{this.state.loading ? (
<Spinner />
) : (
<div className={"row"}>
{this.state.showResult ?
(
this.state.paris.map(details => (
<ResultCard
key={details.id}
id={details.id}
showResultDetail={this.showResultDetail}
prefix={details.prefix}
costPerDay={details.average_cost_per_day}
logoSports={details.infrastructure.map(home =>
home.logo_path.map(path_image => (
<img
src={path_image}
alt="icon-sports"
style={{ width: 20 }}
key={path_image}
/>
))
)}
/>
))
)
:
(
<ResultDetail closeResultDetail={this.closeResultDetails}/>
)
}
</div>
)}
</div>
);
}
}
export default Results;
ResultCard (who is stateless component):
import React from 'react';
import '../../assets/css/ResultCard.css';
const ResultCard = ({prefix, costPerDay, logoSports, showResultDetail, id}) => {
return (
<div className="card" onClick={showResultDetail} id={id}>
<p style={{margin:5}}>{prefix}</p>
<p style={{margin:1}}>arrondissement</p>
<p>{costPerDay} $</p>
{logoSports}
</div>
)
};
export default ResultCard;
ResultDetail (who is stateless component):
import React from 'react';
const ResultDetail = (closeResultDetail) => (
<div onClick={closeResultDetail}>
<p>Result detail</p>
</div>
)
export default ResultDetail;
thank for your help
The issue is here
const ResultDetail = (closeResultDetail) => (
You need to destructure it from the props object like this:
const ResultDetail = ({closeResultDetail}) => (
Or use it from props directly like this:
const ResultDetail = (props) => (
<div onClick={props.closeResultDetail}>
...
in your state component
showResultDetail = () => {
this.setState({ showResult: false });
};
render() {
....
<ResultCard
....
show={this.state.showResult}
//defer the execution of the method
onClick={(e) => this.showResultDetail(e)}/>
}
resultCard.js
const ResultCard = ({prefix, costPerDay, logoSports, showResultDetail, id, show}) => {
if(show)
return (
<div className="card" onClick={showResultDetail} id={id}>
<p style={{margin:5}}>{prefix}</p>
<p style={{margin:1}}>arrondissement</p>
<p>{costPerDay} $</p>
{logoSports}
</div>
);
};
in Results you define
showResultDetail = () => {
this.setState( {showResult: false });
};
as a function without arguments. You then pass
showResultDetail={(e) => this.showResultDetail(e)}
as a function with an event argument to your ResultCard. If you change that to
showResultDetail={this.showResultDetail}
your problem might already be fixed.
Edit: Here is a minimal snippet that does what you're looking for, I think.
const ResultCard = ({showResultDetail, show}) => {
return <div className="card" onClick={showResultDetail}>{show?'Click me!':''}</div>
};
class Results extends React.Component {
state = {
priceValue: "",
showResult: true
};
showResultDetail = () => {
this.setState({ showResult: false });
};
render() {
return <ResultCard show={this.state.showResult}
showResultDetail={this.showResultDetail}/>
}
}
ReactDOM.render(<Results/>, document.getElementById('root'))
.card {
width: 200px;
height: 50px;
background: lightgray;
text-align: center;
line-height: 50px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.6/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.6/umd/react-dom.production.min.js"></script>
<div id='root'></div>

React value returning as undefined

I am trying to map through the data in context and render out a list of cars. But I keep running into some sort of error. I would like to be able to select one of the cars and have it navigate me to another page that displays more details of the car. Current error is (TypeError: value.state.car is undefined). Any help would be great! Current code
Context.js
import React, {Component } from 'react';
import { carInventory } from './data';
export const MyContext = React.createContext();
export class MyProvider extends Component {
state = {
cars: []
};
componentDidMount() {
this.setCars();
}
setCars = () => {
let tempProducts = [];
carInventory.forEach(item =>{
const singleItem = {...item};
tempProducts = [...tempProducts,singleItem];
})
this.setState(()=>{
return {cars:tempProducts}
})
}
getItem = (id) => {
const car = this.state.cars.find(item => item.id === id);
return car;
}
handleDetail = (id) =>{
const car = this.getItem(id);
this.setState(()=>{
return {detailProduct:car}
})
}
render() {
return (
<MyContext.Provider value={{
state: this.state,
handleDetail: this.handleDetail}}>
{this.props.children}
</MyContext.Provider>
)
}
}
VehicleList.js
import React, { Component } from "react"
import './App.css';
import Vehicles from "./Vehicles"
import { MyProvider, MyContext } from "./Context";
export default class VehicleList extends Component {
render() {
return (
<div className="vehicles">
<div className="showcase">
<MyContext.Consumer>
{(value) => (
<React.Fragment>
{value.state.car.map(car => {
return (
<Vehicles key={car.id} car=
{car} />
);
})}
</React.Fragment>
)}
</MyContext.Consumer>
</div>
</div>
)
}
}
import React, { Component } from 'react';
import './App.css';
import { MyProvider, MyContext } from "./Context";
import { Link } from 'react-router-dom';
class Vehicles extends Component {
render() {
const { make, model, id, info, img } = this.props.cars
return (
<div className="col-9 mx-auto col-md-6 col-lg-3 my-3">
<div className="card">
<MyContext.Consumer>
{(value) => (<div className="img-container p-5"
onClick={() =>{
value.handleDetail(id)
}}>
<Link to="/VehicleOverview">
<img src={img} alt="product" className="card-img-top"/>
</Link>
</div>)}
</MyContext.Consumer>
</div>
</div>
)
}
}
export default Vehicles;
This is the kind of thing where static type checkers can really save you some grey hairs.
Your context indeed does not have any property car.
It does, however, have a property cars.
So you should map over cars, i.e. value.state.cars.map(car => ...)
:)

render components from array by changing state

New to and learning React. I have a data file that I am reading in in order to render the Card component for each item. Right now, just one card with nothing in it (one card in the initial state) renders. How do I render multiple components by passing through properties from a data file?
Card.js
import React from 'react';
import * as d3 from "d3";
import data from './../data/data.csv';
class Card extends React.Component {
constructor(){
super();
this.state={
text:[],
}
}
componentDidMount() {
d3.csv(data)
.then(function(data){
console.log(data)
let text = data.forEach((item)=>{
console.log(item)
return(
<div key={item.key}>
<h1>{item.quote}</h1>
</div>
)
})
this.setState({text:text});
console.log(this.state.text);
})
.catch(function(error){
})
}
render() {
return(
<div className='card'>
{this.state.text}
</div>
)
}
}
export default Card
index.js
import Card from './components/Card'
ReactDOM.render(<Card />, document.getElementById('root'));
Answer:
(Found a good explanation here: https://icevanila.com/question/cannot-update-state-in-react-after-using-d3csv-to-load-data)
class Card extends React.Component {
state = {
data: []
};
componentDidMount() {
const self = this;
d3.csv(data).then(function(data) {
self.setState({ data: data });
});
function callback(data) {
this.setState({ data: data });
}
d3.csv(data).then(callback.bind(this));
}
render() {
return (
<div>
{this.state.data.map(item => (
<div className="card" key={item.key}>
<h1>{item.quote}</h1>
</div>
))}
</div>
);
}
}
I'd suggest store the response into a state then render the items with a map, something like:
constructor(){
...
this.state = {
data:[],
}
}
componentDidMount() {
...
.then(data => {
this.setState({
data,
})
})
}
render() {
return (
<div>
{this.state.data.map(item) => (
<div className='card' key={item.key}>
<h1>{item.quote}</h1>
</div>
)}
</div>
)
}

button not working/function not executing

I want to post something(render on the screen) when I press a button.
Pressing the button doesn't give any errors but also doesn't give the result I expect from it. I'm new to react.
import React, { Component } from 'react';
import './style.css';
export default class Main extends Component {
newBlog = () => {
return (
<div>
<Post name = "James" about = "about java" post = "javs is great for complex software apps"/>
</div>
);
}
render() {
return(
<div>
<button onClick = {this.newBlog}>Post-Blog</button>
</div>
);
}
}
class Post extends Component {
render() {
const { name, about, post} = this.props;
return(
<div className = "main">
<h2>{name}</h2>
<h2>{about}</h2>
<hr/><br/>
<p>{post}</p>
</div>
);
}
}
As answer to your comment.
if i understand your point
import uuid from 'uuid/v4'; // get by npm install --save uuid || generate an unique id at each call
class Main extends React.Component {
constructor() {
super();
this.state = {
myBlog: [],
}
}
createNewBlog = () => {
var myPost = { name: 'John', about:'Javascript', post:"i'm john, i'll take about javascript"}
var currentMyBlog = this.state.myBlog;
currentMyBlog.push(myPost);
this.setState({myBlog: currentMyBlog});
};
render() {
return(
<div className=''>
{this.state.myBlog.map(post => (
<div key={uuid()}>
<Post name={post.name} about={post.about} post={post.post}/>
</div>
))}
<button onClick={ () => this.createNewBlog()}> Post blog</button>
</div>
)
}
};
The Returned JSX on button click needs to be rendered somewhere. You are better off setting a visible state on button click as onClick handler on Button doesn't do anything with the returned value in your case. Check the below snippet
class Main extends React.Component {
state = {visible: false}
newBlog = () => {
return (
<div>
<Post name = "James" about = "about java" post = "javs is great for complex software apps"/>
</div>
);
}
toggleVisible = () => {
this.setState(prev => ({visible: !prev.visible}))
}
render() {
return(
<div>
{this.state.visible? this.newBlog(): null}
<button onClick = {this.toggleVisible}>Post-Blog</button>
</div>
);
}
}
class Post extends React.Component {
render() {
const { name, about, post} = this.props;
return(
<div className = "main">
<h2>{name}</h2>
<h2>{about}</h2>
<hr/><br/>
<p>{post}</p>
</div>
);
}
}
ReactDOM.render(<Main/>, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"/>
you should use an arrow function with onClick event.
try that in render of Main component
render() {
return(
<div>
{this.state.visible? this.newBlog(): null}
<button onClick ={() => this.toggleVisible}>Post-Blog</button>
</div>
)
};

Categories