React JS Frontend - Key Error When Rendering List - javascript

I am getting the following error when rendering a list using ReactJS
react-jsx-dev-runtime.development.js:87 Warning: Each child in a list should have a unique "key" prop.
Check the render method of `DriverList`. See https://reactjs.org/link/warning-keys for more information.
at DriverList (http://localhost:3000/static/js/bundle.js:720:13)
at div
at Drivers (http://localhost:3000/static/js/bundle.js:1401:75)
at Routes (http://localhost:3000/static/js/bundle.js:47364:5)
at Router (http://localhost:3000/static/js/bundle.js:47297:15)
at BrowserRouter (http://localhost:3000/static/js/bundle.js:46106:5)
at App
So far I have tried to unsuccessfully resolve it by adding the key value to both the Driver, a higher level div than the Driver object that doesn't need to be there, adding a key to the a React Fragment wrapped around the Driver object. I have tried adding it to each of them individually as well as multiple parts. I have also tried adding the key to the li item within the actual Driver object file that populates the DriverList. I still keep getting the error and I am thinking I am making a stupid mistake somewhere along the code that someone can point out and laugh at me for.
import React from "react"
import Driver from "./Driver"
import Card from "../../shared/components/interface/Card"
import "./DriverList.css"
const DriverList = (props) => {
if (props.items.length === 0) {
return (
<Card key='none'>
<h2>No drivers found.</h2>
</Card>
)
} else {
// Render the List
return (
<ul className='driver-list'>
{props.items.map((driver) => {
return (
<React.Fragment key={driver.id}>
<Driver
key={driver.id}
id={driver.id}
permitno={driver.permitno}
fname={driver.fname}
lname={driver.lname}
mailaddr1={driver.mailaddr1}
mailaddr2={driver.mailaddr2}
dateofbirth={driver.dateofbirth}
driversex={driver.driversex}
licenseidno={driver.licenseidno}
dvrclass={driver.dvrclass}
dvrpermit={driver.dvrpermit}
endorsemnt={driver.endorsemnt}
restricts={driver.restricts}
expdate={driver.expdate}
cmpldate={driver.cmpldate}
numpoints={driver.numpoints}
suspended={driver.suspended}
driver_status={driver.driver_status}
/>
</React.Fragment>
)
})}
</ul>
)
}
}
export default DriverList

try:
props.items.map((driver, idx) => {
return (
<Driver
key={idx}
and see if it helps. And if it does it means that driver.id repeats somewhere

Related

ReactJs page renders fine when using .map of objects but if use index of array runs on first save but crashes on reload

I am creating a flashcard app, already have a page where I use .map() to render all items. Now I created another page so I can individually show one card at a time, so instead of using .map I used items[x] so I can increment by one with a onClick button. When I first save the file the live update renders fine as predicted, yet if I reload the page it crashes saying that it cannot read the word property of undefined. Now after doing some debugging I found that If I console log the array at first it shows up as zero/0 then prints out again with the info, even though I call the useSelector function to gather the info from the state before trying to access the data. Now this happens no matter if I use the .map() function but for some reason the .map() function does not crash and render fine as expected.
import React from "react";
import FlippableFlashcard from "../FlippableFlashcards/FlippableCard/FlippableCard.jsx";
import { Button, Container, Box } from "#mui/material";
import ArrowRightIcon from "#mui/icons-material/ArrowRight";
import ArrowLeftIcon from "#mui/icons-material/ArrowLeft";
import { useSelector } from "react-redux";
import useStyles from "./styles.js";
const Practice = () => {
const classes = useStyles();
const items = useSelector((state) => state.posts);
const handleAdd = () => {};
return (
<>
<Container className={classes.centerDiv}>
<FlippableFlashcard item={console.log(items[0])} />
{/*//This fails, but this does not <FlippableFlashcard item={items.map((item) => console.log(item))} />*/}
</Container>
<Box textAlign="center" className={classes.ButtonBar}>
<Button onClick={handleAdd}>
<ArrowLeftIcon />
</Button>
<Button>
<ArrowRightIcon />
</Button>
</Box>
</>
);
};
export default Practice;
specifically this <FlippableFlashcard item={console.log(items[0])} />
Error:
FlippableCard.jsx:20 Uncaught TypeError: Cannot read properties of undefined (reading 'word')
So I know it is because of that first console log being 0/null/undefined. Tried doing { items && items[0] } as I saw some saying this would work but did not.
Thanks to Akshay Mathur, I just simply did, works great, basically checks if data exists if not then simply console logs fetching, on the second auto reload it will render.
{items.length ? (
<FlippableFlashcard item={items[x]} key={items[x]._id} />
) : (
console.log("fetching data")
)}
Do something like this:
{items.length > 0 && items.map((item,index)=>(<FlippableFlashcard item={item} key={index} />)}

TypeError: Cannot read properties of undefined (reading 'style')

Been stuck on debugging this for quite a while. I'm trying to have a group of items change onClick but with the use of transform but 'style' is undefined. I've also included the Card component functions. Help would be greatly appreciated
import React,{useRef} from 'react';
import { Card } from '../components';
import { CardItemContainer } from './card-item';
export function CardContainer()
{
const listRef=useRef()
const handleClick=(direction)=>
{
if(direction==="left")
{
listRef.current.style.transform=`translate(230)`
}
}
return(
<Card>
<Card.ListTitle> Continue to watch</Card.ListTitle>
<Card.Wrapper >
<Card.ArrowSliderLeft onClick={()=>handleClick('left')}/>
<Card.List ref={listRef}>
<CardItemContainer index={0}/>
<CardItemContainer index={1}/>
<CardItemContainer index={2}/>
<CardItemContainer index={3}/>
<CardItemContainer index={4}/>
<CardItemContainer index={5}/>
<CardItemContainer index={6}/>
</Card.List>
<Card.ArrowSliderRight onClick={() => handleClick("right")}/>
</Card.Wrapper>
</Card>
)
}
Card Components
import {ArrowBackIosOutlined,ArrowForwardIosOutlined} from "#material-ui/icons";
import React, {} from 'react';
import {
Container,
List,
ListTitle,
Wrapper,
ArrowSliderLeft,
ArrowSliderRight
} from './styles/card';
export default function Card({ children, ...restProps }) {
return <Container {...restProps}>{children}</Container>
}
Card.ListTitle=function CardListTitle({children,...restProps})
{
return <ListTitle{...restProps}> {children} </ListTitle>
}
Card.Wrapper=function CardWrapper({children,...restProps})
{
return <Wrapper{...restProps} > {children} </Wrapper>
}
Card.List=function CardList({children,...restProps})
{
return <List{...restProps} >{children}</List>
}
Card.ArrowSliderLeft = function HeaderArrowBackIosOutlinedSymbol({...restProps })
{
return <ArrowSliderLeft {...restProps }>
{/*id allows me to style the icon directly */}
<ArrowBackIosOutlined id="sliderLeft"/>
</ArrowSliderLeft>
}
Card.ArrowSliderRight = function HeaderArrowForwardIosOutlinedSymbol({...restProps}) {
return (
<ArrowSliderRight {...restProps}>
<ArrowForwardIosOutlined id="sliderRight"/>
</ArrowSliderRight>
);
};
Ignore:
Been stuck on debugging this for quite a while. I'm trying to have a group of items change onClick but with the use of transform but 'style' is undefined. I've also included the Card component functions. Help would be greatly appreciated
Function components like CardList don't have a ref property, only class components or DOM elements do.
You haven't posted List component's implementation, but let's assume it has a <ul> tag, and that is what you eventually need to manipulate its .style.transform
CardList >>> List >> ul (this is the element you need to pass the ref)
To pass the listRef all the way to ul from CardList you need to use the forwardRef technique.
Card.List=React.forwardRef(function CardList (props,ref)
{
const {children,...restProps} = props
return <List{...restProps} ref={ref} >{children}</List>
})
the List component itself :
const List = React.forwardRef(function (props,ref) {
return <ul ref={ref}>
... the implementation of your List
Now you can pass listRef in here and it goes down the chain:
<Card.List ref={listRef}>
Side Note: taking from Drew Reese's comment on this answer, since CardList is just transfering the same props from a parent component to List, you can simply assign List to Card.List, then only one step of ref forwarding would be enough:
Card.List = List // CardList component isn't used anymore.
The same thing could work for Card.ListTitle and Card.Wrapper:
Card.ListTitle=ListTitle
Card.Wrapper=Wrapper
I too have just faced this same issue, and have tried to get my code working again. Checking similarity between your given code and my erroneous code snippet helped me fix the error.
Strangely, I have faced this error with a JSX multi-line comment in place after my element (MUI <Snackbar> element, in my case).
Error(s):
My code snippet looked something like:
<Snackbar open={snackbarOpen} autoHideDuration={5000} onClose={()=>setSnackbar(false)} > {/* My Comment Here */}
<>...</>
</Snackbar>
Quite similar place of JSX comment as your Card Component
Card.ArrowSliderLeft = function
...
return <ArrowSliderLeft {...restProps }>
{/*id allows me to style the icon directly */}
<ArrowBackIosOutlined ... />
</ArrowSliderLeft>
Removing just the comment part {/* */} immediately following an opening tag worked for me.
So, try removing your JSX comment or placing it elsewhere,and see if it helps.
Sharing it here just for my and others future reference. :)

React beautiful DND - I get "Unable to find draggable with id: 1"

In the code below the UI renders two "Column" components and each column contains two draggable elements called "Tasks". When the user drags a "Task" between columns the code works - up to a point. When the user continuously drags the task components around eventually they will stop dragging and the user gets an error that says:
Unable to find draggable with id: X
I don't know why this happens nor how to fix it.
Note: I am assuming the way the library works is when you drag elements you need to reorder and update your state in the onDragEnd function.
Here is my code:
app.js
import React,{useState} from 'react';
import {DragDropContext} from 'react-beautiful-dnd';
import helper from './helper_functions'
import Column from './Components/Column';
function App() {
let initialState = [
{
groupName:"Today",
tasks:[
{id:"1", title:"Test-1"},
{id:"2", title:"Test-2"}
]
},
{
groupName:"Tomorrow",
tasks:[
{id:"3", title:"Test-3"},
{id:"4", title:"Test-4"}
]
},
]
const [taskList, setTasks] = useState(initialState)
function onDragEnd(val){
let result = helper.reorder(val.source,val.destination,taskList);
setTasks(result)
}
return (
<DragDropContext onDragEnd={onDragEnd}>
<Column droppableId="Today" list= {taskList[0].tasks} type="TASK"/>
<Column droppableId ="Tomorrow" list = {taskList[1].tasks} type="TASK"/>
<div> context hello world </div>
</DragDropContext>
);
}
export default App;
src/helper_functions
export default {
reorder:function(source,destination,taskDataArr){
let taskData = [...taskDataArr]
// //_____________________________________________________________Source data
let sourceGroupIndex = taskData.findIndex((val, index) => { // iterate and find "Today" (or other) index in list data
return val.groupName === source.droppableId
});
let draggedTask = taskData[sourceGroupIndex].tasks.find((val, index) => { // Get specific task object based on index
return source.index === index
}); // dragged object
let sourceListCopyWithElementRemoved = taskData[sourceGroupIndex].tasks.filter((val, index) => {
return index !== source.index // removes dragged element from array
});
// //__________________________________________________________________Destination data
let destinationGroupIndex = taskData.findIndex((val, index) => { // iterate and find "Tomorrow" (or other) index in list data
return val.groupName === destination.droppableId
});
taskData[destinationGroupIndex].tasks.splice(destination.index, 0, draggedTask); // insert dragged item to new place
taskData[sourceGroupIndex].tasks = sourceListCopyWithElementRemoved
return taskData
}
}
src/Components/Column
import React from 'react';
import {Droppable} from 'react-beautiful-dnd';
import Task from "../../Components/Task"
function Column(props){
const { classes, droppableId, list, type} = props;
let style = {
backgroundColor:"orange",
height:"300px",
width:"400px",
margin:"100px"
}
console.log(list)
return (
<Droppable droppableId = {droppableId} type={type}>
{provided => (
<div {...provided.droppableProps} ref={provided.innerRef} style={style}>
<h2>{droppableId}</h2>
{list.map((val,index)=>{
return <Task id={val.id} key={index} index={index} title={val.title}/>
})}
{provided.placeholder}
</div>
)
}
</Droppable>
)
}
export default Column
src/Components/Task
import React from 'react';
import {Draggable} from 'react-beautiful-dnd';
function Task(props){
const { classes, id, index,title } = props;
let style = {
backgroundColor:"red",
}
return (
<Draggable draggableId ={id} index={index} type="TASK">
{(provided) => (
<div
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
>
<h4 style={style}>{title}</h4>
</div>
)}
</Draggable>
)
}
export default Task
There are a few issues with your code:
Error Unable to find draggable with id: X
In the Column component you used index as a key for the tasks. I think this is what causes this error.
Using the task id as key, in Column, makes this error go away.
reorder has some issues:
it removes a task when dropped in the same column
raises an error when a task is dropped outside the columns
I had a bit of fun with you code and tried another way to reorder. This way of reordering might come in handy if you ever add a more columns - there is still room for improvements.
Hope it helps!
If you are getting this error on React 18
Unable to find draggable with id:
Try removing StrictMode
Not for this case, but
For every one - check provided.draggableProps not provided.dropableProps
<Draggable draggableId ={id} index={index} type="TASK">
{(provided) => (
<div
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
>
<h4 style={style}>{title}</h4>
</div>
)}
</Draggable>
RBD try find node by provided.draggableProps. Missing this props got error: Unable to find draggable with id: X
I had a similar issue, I was mapping through multiple draggable and had missed the key prop,
Adding the key to Draggable fixed the issue for me
{tasks.map((t, index) => (
<Draggable
draggableId={t._id}
index={index}
key={t._id} >
....
</Draggable>
}
For Error:
Unable to find draggable with id: X
Remove Strict mode in React js.
If you are using Next.js you can find the strict mode in next.config.js file
For Error:
Invariant failed: Draggable[id: 1]: Unable to find drag handle do the following
{process.browser && (
<section>
<DragDropContext onDragEnd={onDragEnd}>
//Your code with droppable and draggable
</DragDropContext>
</section>
)}
Related issue
I ran into the same issue however the following steps helps me
Step 1:
draggableId should be string, not an integer
as per https://github.com/atlassian/react-beautiful-dnd/issues/1512
Step 2:
if you are coming from EggHead tutorial, this might have missed.
Try to add a key property as mentioned in the top answer
<Draggable key={item.id} draggableId={item.id.toString()} index={index} >
Try converting the integer value to a string. It'll solve the issue as it solved mine
{tasks.map((t, index) => (
<Draggable
draggableId={t._id.toString()}
index={index}
key={t._id} >
....
</Draggable>
}
There is a YouTube lesson on react-beautiful-dnd. He posted his
lesson progress in the Code Sandbox enter link description here
You can open it and make sure. But I have on "react": "^18.1.0" does
not work and gives an error
Unable to find draggable with id:X
And on older versions of react everything also works without
errors.Try for example another version of react"^17.0.2"ю It worked
for me
Also remember, when installing the react-beautiful-dnd library, were there any dependency conflicts? Maybe you have not established all the connections and because of this it does not work correctly. In any case, as a test, I suggest downloading the code from the lesson and checking in my project whether it works or not. If it works, it means an error in the code, if not, then react-beautiful-dvd does not work correctly
I hope this will help someone. If you are experiencing this even your code is correct. Please check your react version. In react version 18.0, dnd will show unable to find draggable with id warning. Current solution to downgrade to 17 and it works flawlessly. I searched for the solution like remove strict mode, using dynamic import and other things but currently it's related to react 18.
Post it here, since this is the top link the Google for the same error.
It might be the case, that you do not render an element with the provided.dragHandleProps
<div>
{someCondition && (
<div>
<DragIndicatorIcon {...provided.dragHandleProps}/>
</div>
)}
</div>
In this case move {...provided.dragHandleProps} outside the condition
<div {...provided.dragHandleProps}>
{someCondition && (
<div>
<DragIndicatorIcon {...provided.dragHandleProps}/>
</div>
)}
</div>
Found this solution here
Resolved this issue by converting draggableId into string
Removing <React.StrictMode> fixed it for me.
It works with react-beautiful-dnd and React 18 in StrictMode.
https://github.com/atlassian/react-beautiful-dnd/issues/2399#issuecomment-1175638194

How to render multiple items from an API call using React

I am using axios to get the data from an API. My component has an articles array in the state which is where the data from the API request will go.
I am still really new to React and trying to find information on displaying multiple articles on the page. That is what I am trying to figure out. Maybe I am using this.state wrong?
I've also tried fetch() then using a .then() to return the information. Neither way has helped me achieve what I am trying to display:
import React from "react";
import axios from "axios";
class Pages extends React.Component{
constructor(){
super();
this.state = {
articles : []
}
}
componentDidMount(){
this.getArticles().then(res =>
{
console.log(res);
this.setState({articles : res.data.articles});
});
}
getArticles(){
return axios.get('https://newsapi.org/v2/everything?domains=wsj.com,nytimes.com&apiKey=API_KEY');
};
render(){
return (
<div className="ui raised very padded text container segment">
<p>
Yo!
{this.state.articles[0] ? this.state.articles[0].author : ''}
</p>
</div>
);
}
}
export default Pages;
In the return section I want to display the article name, author, url link, and the content of the article.
If I understand correctly, you're wanting to render all articles that are available after your axios request completes.
To achieve that, consider using the map() method on the state.articles array. This allows you to "map" each item from the raw document JSON data to an <li> element containing the article information that you want to display to your users.
When rendering each <li>, you can access the content of the current article being mapped, to render that into the components overall rendered result:
render(){
return (
<div className="ui raised very padded text container segment">
<ul>
{ this.state.articles.map((article, index) => {
return (<li key={index}>
<h2>{ article.name }</h2>
<div>{ article.author }</div>
<p>{ article.content }</p>
<a href={article.url}>{ article.url }</a>
</li> )
})}
</ul>
<p>Yo!</p>
</div>
);
}
Something also to note is that, when rendering lists in React, you should include a unique key for each list item rendered (in the code above, the key is specified as the index of the article being mapped).
Update
To render the first article only (if present) while retaining your component's current state structure, you could slice() the articles array before performing the map(). This would cause a new array (with only the first article) to be passed to map() - the end result being that only the first article is rendered:
{ this.state.articles.slice(0,1).map((article, index) => {
/* Existing code from answer */
}}

"A valid React element (or null) must be returned." with array.map

I have the Functional React component defined below:
import React from 'react';
import Cell from './FeedCell';
import PropTypes from 'prop-types';
const Feed = (props) => {
return props.arr.map((type, index) => {
return (<Cell />)
})
};
I am getting the error:
Feed(...): A valid React element (or null) must be returned. You may have returned undefined, an array or some other invalid object.
I feel like this should be obvious but I have tried the solutions presented online but I am missing something.
You are currently returning an array, but you must return a proper React element.
You can wrap your array in a React.Fragment if you don't want a wrapping element in the DOM.
const Feed = (props) => {
return (
<React.Fragment>
{props.arr.map((type, index) => <Cell />)}
</React.Fragment>
);
};
You need to wrap your array in some element
If you don't want to wrap your FeedCells in an actual element, you can use React.Fragment instead:
const Feed = (props) => {
return (
<React.Fragment>
{ props.arr.map((type, index) => <Cell />) }
</React.Fragment>
);
};
More information here:
https://reactjs.org/docs/fragments.html
Can you add more information? - FeedCell code and the parent of Feed.
Try console logging the props and check if props.disputesToRender actually exists or has value in all your render calls.
Check if FeedCell actually returns html or a component that returns an html.
You should also add a <div> or <React.Fragment> to enclose your return method. Since there should always be a single parent on returns.

Categories

Resources