I'm trying to display a list of product features from some local JSON data using React, but my map/list functionality isn't displaying anything onto the DOM.
I originally had imported react-render-html, but it wasn't compatible so I had to remove it.
Here's my productHighlights:
class ProductHighlights extends Component {
constructor(props) {
super(props);
this.state = {
data: null
}
}
componentWillReceiveProps(newProps) {
const index = newProps.selected;
const productData = Number.isInteger(index) ? newProps.productData[index] : null;
if (productData !== null) {
this.setState({ data: productData });
}
}
getFeatureList = (itemDescription) => {
itemDescription[0].features.map((feature, index) => (
<li key={index}>{feature}</li>
))
}
render() {
const itemDescription = this.state.data ? this.state.data.ItemDescription : null;
const featureList = itemDescription ? this.getFeatureList(itemDescription) : null;
console.log(itemDescription);
console.log('item description = ' + itemDescription);
return (
<div className="product-highlights-container">
<div className="product-highlights-title">product highlights</div>
<ul className="product-features">
{featureList}
</ul>
</div>
)
}
}
export default ProductHighlights;
Logging itemDescription to the screen shows [{...}], which then opens to > 0 > 'features: Array(10). I'm not sure whygetFeaturedList` isn't getting this info successfully.
What is the error message you are getting in the console?
Your map is implicitly returning undefined. You need to return the element.
itemDescription[0].features.map((feature, index) =>
{
return (<li key={index}>{feature}</li>);
}
)
I got it to display - all I had to do was add spaces around feature in this line in my getFeatureList function:
<li key={index}>{ feature }</li>
Only thing now is that the tags are displaying in the list. I may need to parse.
Related
I'm trying the scenario in the ReactJS application like.
created dummy data in App.js itself with name and id, crated another component with List.js where displaying the list items.
If I selected any of the list item it should be move the item to top like below
before
A
B
C
after
B
A
C
I created function in List.js file but it not working
//----App.js-------
import "./styles.css";
import List from './List'
const data = [
{id:1,letter:"A"},
{id:2,letter:"B"},
{id:3,letter:"C"},
]
export default function App() {
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<List items={data}/>
</div>
);
}
//----List.js-------
import React from 'react';
import {useState} from 'react'
export default function List({items}){
console.log(items);
const [selectedIndex,setSelectedIndex] = useState(0)
const selectList = (items,ind)=>{
console.log(ind+1);
const arr = Object.entries(items,ind)
setSelectedIndex(()=>{
arr.sort((a,b)=>{
return a.id===ind+1?-1:b.id===ind+1?1:0
})
})
// console.log(items,ind);
}
return(
<div>
<ul>
{/* {console.log(items)} */}
{items.map((item,ind)=>{
return(
<li key={ind} onClick={()=>selectList(item,ind)}>{item.letter}</li>
)
})}
</ul>
</div>
)
}
Just try this approach. First create items state that will hold the data.
const [items, setItems] = useState(data);
Next create a reorder function where you pass the clicked id.
const reorder = (id) => {
...
}
Inside the function, we declare the first item that the value will be assigned during filtration later.
And then define a filter function where we get the first item by its id, put it inside an array, and assign it to the firstItem variable. The filter iteration process should result in filteredItems (exclude the clicked item).
Then, clone both firstItem and filteredItems by using shallow copy, set as items by using setItems setter.
const reorder = (id) => {
let firstItem;
const filteredItems = items.filter((item) => {
if (item.id === id) {
firstItem = [item];
return false;
}
return true;
});
setItems([...firstItem, ...filteredItems]);
};
Then, we can render it like this:
<ul>
{items.map((item) => (
<li onClick={() => reorder(item.id)}>
{item.letter}
</li>
))}
</ul>
For example:
Since you need to update the order of the items, it's better to have items as a state property.
To initialize state with props, getDerviedStateFromProps should be used.
class List extends Component {
constructor(props) {
super(props);
this.state = {selectedIndex: 0, items: []};
}
static getDerivedStateFromProps(props, state) {
return {items: props.items};
}
selectListItem=(id,ind)=> {
this.setState((state,props)=> {
let excludingSelected = state.items.filter((itm,i)=> ind != i);
return {
items: [state.items[ind]].concat(excludingSelected),
selectedIndex: ind
};
}
}
}
Prefer id as key to index (docs).
import React from 'react';
export class Books extends React.Component {
state = {
loading: true,
books: []
}
componentDidMount() {
fetch('**url**')
.then(res => res.json())
.then((data) => {
this.setState({ books: data })
})
.catch(console.log)
}
render() {
const { books } = this.state;
console.log("this.state contains:", this.state);
/* this.state contains: {loading:true, books: status:'success',data:(10)[{id:1, name:xyz,..},{}..] */
const b = books.data;
return (
<div>
{b.map((k) => (
<h1>{k.name}</h1>
))}
</div >
);
}
}
I want to display all the values(for example: id:1, name:xyz, id:2 , name:xxx)
Since 1 week I'm trying to fix this. But couldn't. getting map is not a function.
Please help me to fix this issue.
try following:
let b = books.data || [];
since you're getting data in componentDidMount, there's fair chance it doesn't get the result when you want to render.
The books object in the state is initially empty, therefore books.data does not exist and hence books.data.map is not function. So do conditional render
const {data} = this.state.books
<div>
{data && data.map((k) => (<h1>{k.name}</h1>))}
</div >
Try making a condition to check if b is an array or not! like this:
const b = books.data;
return (
<div>
{
if(Array.isArray(b)){
b.map((k) => (
<h1>{k.name}</h1>
))
}
}
</div >
);
}
I would like to find an object based on its id then render it in a component.
getInitialState() {
return { item: [] }
},
componentDidMount() {
this.setState({item: this.props.items.filter(item => (item.id == this.props.match.params.id))})
}
componentDidUpdate() {
console.log(this.state.item) // result is empty array
}
If I do not want to use setState and find object in render method then I will get:
render() {
var item = this.props.items.find(item => (item.id == this.props.match.params.id))
console.log(item) // First it is undefined then it will be found
var title = item.title
return (
<div>
{title}
</div>
How can I find object based on the params.id then render it inside the component?
render() {
var item = this.props.items.find(item => (item.id == this.props.match.params.id))
//This is what you should do to show that it's loading.
if(!item || !item.id){
return <div>Loading</div>
}
console.log(item) // First it is undefined then it will be found
var title = item.title
return (
<div>
{title}
</div>
I am trying to get scrollPosition using getSnapshotBeforeUpdate lifecycle method. I went through below React official site to understand about new life cycle method getSnapshotBeforeUpdate
But I am not able to find any scroll position. I console.log all the output, but didn't find anything in console.
This is my code file:
import React from 'react';
class ScrollingList extends React.Component {
constructor(props){
super(props);
this.listRef = React.createRef();
}
getStaticContent() {
const result = [];
for( let i= 1; i <=100; i++){
result.push(<li key={i}>{i} > This is paragraph line-{i}</li>);
}
return result;
}
getSnapshotBeforeUpdate(preProps, preState) {
// const list = this.listRef.current;
// console.log(list);
if(preProps.list.length > this.props.list.length) {
const list = this.listRef.current;
console.log(list);
return list.ScrollingHeight - list.ScrollTop;
}
return null;
}
componentDidUpdate(preProps, preState, snapshot) {
console.log(snapshot);
if (snapshot !== null) {
const list = this.listRef.current;
list.scrollTop = list.scrollHeight - snapshot;
}
}
render() {
return(
<div ref={this.listRef}>
{/* <div className="content-wrap">
<ul>
{this.getStaticContent()}
</ul>
</div> */}
</div>
);
}
}
export default ScrollingList;
Error: TypeError: Cannot read property 'length' of undefined
How I can get scroll position using this life cyle method?
You have use OffsetHeight and scrollTop , please try this modified code.
getSnapshotBeforeUpdate(preProps, preState) {
if(preProps.list.length > this.props.list.length) {
const list = this.listRef.current;
console.log(list);
const { current } = this.listRef;
const isScrolledToBottom =
current.scrollTop + current.offsetHeight >= current.scrollHeight;
return { isScrolledToBottom };
}
return null;
}
I want to iterate through each element in the array and display it in the breadcrumb navigation.
What i am trying to do?
from a particular path or location say /list/item_id and if the item has certain information my breadcrumb navigation should change to the hierarchy of information.
For example, say i have the information of the item stored in item_information...and it is array of objects as below,
const item_information = [
{
name: "c_name",
},
{
name: "a_name",
},
{
name: "name",
}
I want to retreive only the name of each object and store it in variable display and want to display that in the breadcrumb navigation....so to loop through each name value from the variable display i use .map function. In doing so , i get an error .map is not a function.
Below is the code,
class Crumb extends React.PureComponent {
render = () => {
const link = this.props.link;
let display;
let match;
let after_link;
if (link === '/') {
display = 'Home';
} else if (match = link.match(/^\/list\/new$/)) {
display = 'new item';
} else if (match = link.match(/^\/list\/([^/]+)$/))
if (this.props.item_information > 0) {
display = this.props.item_information.map((el) => {
return el.name;
});
} else {
const model_id = match[1];
const model = this.props.models && this.props.models.find(model
=> '' + model.id === model_id);
display = itemname;
after_link = 'after_link';
}
}
//last part of the link
if (!display) {
const parts = link.split('/');
display = parts[parts.length - 1];
}
return (
<div>
{Array.isArray(display) && display.map((display) => {
return (
<div className="crumb">
<Link to={link}>{display}</Link>
</div>
);
})}
<div className="crumb">
<Link to={link}>{display}</Link>
</div>
{after_link}</div>
);
};
}
class Breadcrumb extends React.PureComponent {
render = () => {
const path = this.props.location.pathname;
const crumbs = [];
path.split('/').slice(1).forEach((part, index, parts) => {
crumbs.push('/' + parts.slice(0, index + 1).join('/'));
});
return (
<div className="breadcrumb">
{crumbs.map((link, i) => {
return (
<Fragment key={link}>
<Crumb
item_information={this.props.item_information}/>
</Fragment>);
})}
</div>
);
};
}
Could someone help me in getting rid off the error .map is not a function. thanks.