I am trying to use Radium in react - reactjs

So I have two components, Person and App, the person component has some inline CSS styling that I was to use with react, but I am getting the following error.
Module '"../../../../../../Users/7oss/Desktop/ReactTutorials/my-first-portfolio/node_modules/#types/radium"' has no exported member 'StyleRoot'.ts(2305)
I am trying to add #media styling to the Person Component.
I have tried doing Radium.StyleRoot instead of StyleRoot, but I got the following error:
Objects are not valid as a React child (found: object with keys {#media (min-width: 500px)}). If you meant to render a collection of children, use an array instead.
Here is the App Component:
import React, { Component, ChangeEvent } from "react";
import "./App.css";
import Person from "./Components/Person/Person";
import Radium, { StyleRoot } from "radium";
class App extends Component {
state = {
persons: [
{ id: "hoba", name: "Hosam", age: 24 },
{ id: "hoba1", name: "Ayah", age: 18 },
{ id: "hoba2", name: "Test", age: 20 }
],
ShowPersons: false
};
deletePersonHandler = (personIndex: any) => {
// const persons = this.state.persons.slice(); this is one way
const persons = [...this.state.persons]; // Another way
persons.splice(personIndex, 1);
this.setState({ persons: persons });
};
nameChangeHandler = (event: any, id: any) => {
// console.log('Was clicked!!');
// this.state.persons[0].name = "7ossam" DON'T DO THIS!!! USE SETSTATE()
const personIndex = this.state.persons.findIndex(p => {
return p.id === id;
});
const person = { ...this.state.persons[personIndex] };
person.name = event.target.value;
const persons = [...this.state.persons];
persons[personIndex] = person;
this.setState({
persons: persons
});
};
togglePersonsHanddler = () => {
const doesShow = this.state.ShowPersons;
this.setState({ ShowPersons: !doesShow });
};
render() {
const style = {
backgroundColor: "green",
color: "white",
font: "inherit",
border: "1px solid",
cursor: "pointer",
":hover": {
backgroundColor: "lightgreen",
color: "black"
}
};
let persons = null;
if (this.state.ShowPersons) {
persons = (
<div>
{this.state.persons.map((person, index) => {
return (
<Person
name={person.name}
age={person.age}
click={() => this.deletePersonHandler(index)}
key={person.id}
changedName={(event: any) =>
this.nameChangeHandler(event, person.id)
}
/>
);
})}
</div>
);
style.backgroundColor = "red";
style[":hover"] = {
backgroundColor: "salmon",
color: "black"
};
}
let classes = [];
if (this.state.persons.length <= 2) {
classes.push("red");
}
if (this.state.persons.length <= 1) {
classes.push("bold");
}
return (
<StyleRoot>
<div className="App">
<br />
<p className={classes.join(" ")}>Yasta garab el hoba hoba</p>
<button style={style} onClick={this.togglePersonsHanddler}>
Toggle Names
</button>
<br />
<h1>Hello, this is sam!</h1>
{persons}
</div>
</StyleRoot>
);
}
}
export default Radium(App);
And here is the Person Component:
import React, { Component } from "react";
import Radium from "radium";
import "./Person.css";
interface IPersonProps {
name: string;
age: number;
click?: any;
changedName?: any;
}
class Person extends Component<IPersonProps> {
render() {
const style = {
"#media (min-width: 500px)": {
width: "450px"
}
};
return (
<div className="Person">
{" "}
style={style}
<p onClick={this.props.click}>
{" "}
I am {this.props.name} and I am {this.props.age} years old
</p>
<p>{this.props.children}</p>
<input
type="text"
onChange={this.props.changedName}
value={this.props.name}
/>
</div>
);
}
}
export default Radium(Person);
Here is the radium package in package-lock.json:
"#types/radium": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/#types/radium/-/radium-0.24.2.tgz",
"integrity": "sha512-AudCpKQH/csx6eB4OZhEdKf8Avm18wX8gLOig5H5iocPDPp3GRUPkQmUOXvsIYO64LyAb4CiIfSmcWUaUdvl4A==",
"requires": {
"#types/react": "*"
}
},
I am assuming that the issue is with StyleRoot isn't imported correctly somehow, but I would appreciate some input. I am also Using TypeScript

I had the same problem. I managed to solve by making the typing of the constant style explicit.
const style: Radium.StyleRules = {
'#media (min-width: 500px)': {
width: '450px'
}
};

Related

How to Make Gutenberg Repeater Field

Want to make a Quiz application on WordPress Gutenberg with React? The problem goes, when I try to make a repeater field of the quiz section. I use UseState to make the components Repeat the section onClick. But I can't edit the input field after repeating it.
index.js
import { registerBlockType } from "#wordpress/blocks";
import "./style.scss";
import Edit from "./edit";
import save from "./save";
import metadata from "./block.json";
registerBlockType(metadata.name, {
attributes: {
ids: { type: "array", default: 1},
question: { type: "string", default:"Example Question"},
answers: { type: "array", default: [""] },
correctAnswer: { type: "number", default: undefined },
bgColor: { type: "string", default: "#ededed" },
},
edit: Edit,
save,
});
edit.js `
import { __ } from "#wordpress/i18n";
import {
TextControl,
Flex,
FlexBlock,
FlexItem,
Button,
Icon,
} from "#wordpress/components";
import { useBlockProps } from "#wordpress/block-editor";
const { useState} = wp.element;
import "./editor.scss";
import QuizWrapper from "./components/QuizWrapper";
import TestComponent from "./components/TestComponent";
export default function Edit(props) {
const [quizwrapper, setQuizwrapper] = useState([<QuizWrapper props={props} key={0} />])
const blockProps = useBlockProps({
className: "quiz-wrapper",
});
function addSection() {
setQuizwrapper([...quizwrapper,<QuizWrapper props={props} key={quizwrapper.length} />]);
}
return (
<div {...blockProps}>
<QuizWrapper props={props}></QuizWrapper>
{quizwrapper}
<Button isPrimary onClick={addSection}>
Add Another Section
</Button>
</div>
);
}
When I use <QuizWraper /> as a component it works fine on editing and changing on Question and Answer section, image has been uploaded below
but for the UseState hook for repeating the component {quizwrapper} repeates the section but doesn't allow me to edit and change the section
Image of the editor WordPress dashboard
QuizWrapper.jsx
import React from 'react'
import Question from "./Question"
import Answers from "./Answers"
const QuizWrapper = ({props}) => {
return (
<div className='quizes'>
<Question props={props}></Question>
<Answers props={props}></Answers>
</div>
)
}
export default QuizWrapper
Question.js
import { TextControl } from "#wordpress/components";
export default function Question({props}) {
function updateQuestion(value) {
props.setAttributes({ question: value });
}
return (
<div className="question">
<h2 style={{ fontSize: "20px", margin: "20px 0 8px 0" }}>Questions: </h2>
<TextControl
value={props.attributes.question}
onChange={updateQuestion}
/>
</div>
);
}
Answer.js
import { TextControl, Button, Icon } from "#wordpress/components";
export default function Answers({ ids, props }) {
function markasCorrect(index) {
props.setAttributes({ correctAnswer: index });
}
function deleteAnswer(indextoDelete) {
const newAnswer = props.attributes.answers.filter(function (x, index) {
return index != indextoDelete;
});
props.setAttributes({ answers: newAnswer });
if (indextoDelete == props.attributes.correctAnswer) {
props.setAttributes({ correctAnswer: undefined });
}
}
return (
<div className="answers" key={ids}>
<p style={{ fontSize: "13px", margin: "20px 0 8px 0" }}>Answers: </p>
{props.attributes.answers.map((answer, index) => {
return (
<div className="answer-wrapper">
<Button onClick={() => markasCorrect(index)}>
<Icon
className="mark-as-correct"
icon={
props.attributes.correctAnswer == index ? "yes-alt" : "yes"
}
/>
</Button>
<TextControl
value={answer}
onChange={(updateanswer) => {
const newAnswers = props.attributes.answers.concat([]);
newAnswers[index] = updateanswer;
props.setAttributes({ answers: newAnswers });
}}
></TextControl>
<Button
isLink
className="deleteBtn"
onClick={() => deleteAnswer(index)}
>
Delete
</Button>
</div>
);
})}
<Button
isPrimary
onClick={() => {
props.setAttributes({
answers: props.attributes.answers.concat([""]),
});
}}
>
Add Another Answer
</Button>
</div>
);
}
Need Solution: How I can make the repeater section of the <Quizwapper>component and how I can make the repeater section where the <Question/> and <Answer/> components will work fine.

How to improve performance for the web without freezing or lagging when making multiple API calls at the same time?

Currently I am working on a function that exports components to PDFs
`
import { PDFExport } from "#progress/kendo-react-pdf";
import { useAppDispatch, useAppSelector } from "hooks";
import { get } from "lodash";
import { ManagerGeotechnicalDetail } from "pages/GeotechnicalDetail";
import PointDetail from "pages/PointDetail";
import DataChilAnalyticsDetails from "pages/Project/DataChildAnalyticsDetails";
import { FC, useEffect, useRef } from "react";
import { getListPoints } from "store/actions/datamap";
import { ETypeParent } from "../../state/reducer";
interface Props {
dataOverview: any[];
title: string;
idButton: string;
}
const DownloadPDF: FC<Props> = ({ dataOverview, title, idButton }) => {
const dispatch = useAppDispatch();
const [dataPointsSelected, projectState] = useAppSelector((state) => [
state.datamap.data,
state.project.project,
]);
const pdfExportComponent = useRef<PDFExport>(null);
useEffect(() => {
if (projectState.projectnumber) {
dispatch(
getListPoints(
get(projectState, "bounds"),
projectState,
dataPointsSelected.dataSummaryPoints
)
);
}
//eslint-disable-next-line
}, [projectState]);
const renderUIPDF = (data) => {
switch (data.typeChild) {
case ETypeParent.RAW_DATA:
return (
<PointDetail
match={{
params: {
idpoint: data.pointid,
id: projectState.projectid,
isHideForExport: true,
},
}}
/>
);
case ETypeParent.ASSIGNING_GEOLOGICAL_UNITS:
return (
<ManagerGeotechnicalDetail
match={{
params: {
idpointGeotechnical: data.pointid,
id: projectState.projectid,
isHideForExport: true,
},
}}
/>
);
case ETypeParent.DATA_ANALYTICSANALYTICS:
return (
<DataChilAnalyticsDetails
match={{
params: {
idDataChildAnalytics: data.childanalysisid,
id: projectState.projectid,
isHideForExport: true,
},
}}
/>
);
default:
return;
}
};
return (
<div>
<div className="example-config">
<button
id={idButton}
className="btn btn-success mt-2 me-4 k-button k-button-md k-rounded-md k-button-solid k-button-solid-base"
onClick={() => {
if (pdfExportComponent.current) {
pdfExportComponent.current.save();
}
}}
disabled={title.length === 0}
>
Export PDF
</button>
</div>
<div className="hide-ui">
<PDFExport
paperSize="A3"
forcePageBreak=".page-break"
landscape={true}
ref={pdfExportComponent}
fileName={title}
title={title}
scale={0.6}
margin={{
top: "0.75cm",
left: "3.6cm",
right: "3.6cm",
bottom: "0.75cm",
}}
>
{dataOverview &&
dataOverview.map((data, index) => (
<div
key={index}
style={{
width: "1620px",
}}
>
{renderUIPDF(data)}
{index !== dataOverview.length - 1 && (
<div className="page-break" />
)}
</div>
))}
</PDFExport>
</div>
</div>
);
};
export default DownloadPDF;
`
The problem I am facing now is when the dataOverview list has many objects, it will map the data to the components in renderUIPDF then I will call multiple APIs at the same time in those components.
At that time, there will be lag or website freeze :(
So is there any way I can improve the performance of my website without lag, freeze when calling too many APIs at once, the number can be up to more than 100 APIs at once?

validation for react-select, getting Cannot read property 'length' of undefined

I am new to react and am using react-select for selecting the respective departments. I am trying to validate the select dropdown such that if select dropdown is empty it will give an error message. I am not sure how to do that exactly. It is showing this error:
Departments.continue
D:/react_bpms1/src/components/Departments.js:69
66 | this.setState({ selectedOptions });
67 | };
68 | continue = e => {
> 69 | if (document.getElementById("Departments").value.length < 1) {
| ^ 70 | document.getElementById("departments").style.visibility = "visible";
71 | document.getElementById("Departments").style.border = "1px solid red";
72 | } else {
But here is what I am doing:
const Departments = [
{ label: "OneIT", value: "OneIT" },
{ label: "HR", value: "HR" },
{ label: "Vigilance", value: "Vigilance" },
{ label: "Ethics", value: "Ethics" },
{ label: "Corporate Services", value: "Corporate Services" },
{ label: "Legal", value: "Legal" },
{ label: "Sports", value: "Sports" },
{ label: "TQM", value: "TQM" },
{ label: "Iron Making", value: "Iron Making" },
{ label: "TMH", value: "TMH" }
];
class MultiSelect2 extends Component {
state = {
selectedOptions: []
};
handleChangeField = selectedOptions => {
this.setState({ selectedOptions });
};
render() {
const { selectedOption } = this.state;
return (
<div className="container">
<div className="row">
<div className="col-md-2"></div>
<div className="col-md-8">
<span>Select Department</span>
<Select
id="Departments"
htmlFor="Departments"
value={selectedOption}
options={Departments}
onChange={this.handleChangeField}
isMulti
/>
{this.state.selectedOptions.map(o => (
<p>{o.value}</p>
))}
</div>
<div className="col-md-4"></div>
</div>
</div>
);
}
}
export default MultiSelect2;
Here is where I am calling the Multiselect option:
export class Departments extends Component {
state = {
rows: [],
idx: [],
selectedOptions: []
};
handleChangeField = selectedOptions => {
this.setState({ selectedOptions });
};
continue = e => {
if (document.getElementById("Departments").value.length < 1) {
document.getElementById("departments").style.visibility = "visible";
document.getElementById("Departments").style.border = "1px solid red";
} else {
e.preventDefault();
this.props.nextStep();
}
};
back = e => {
e.preventDefault();
this.props.prevStep();
};
render() {
const { values, handleChange } = this.props;
const { selectedOption } = this.state;
const {
values: {
Title,
Details,
What,
Why,
How,
Status,
Cost,
Benefits,
Kpi_Before,
Kpi_After,
UOM_Before,
UOM_After,
Base_After,
Target_After,
dateTime_After,
Base_Before,
Target_Before,
Time,
dateTime,
departments,
Departments,
selectedOptions
}
} = this.props;
return (
<MuiThemeProvider theme={theme}>
<React.Fragment>
<div className={useStyles.root}>
<AppBar position="static">
<Toolbar>
<Typography
gutterBottom
align="center"
style={{ width: "100%", alignItems: "center" }}
>
Select Departments
</Typography>
</Toolbar>
</AppBar>
</div>
<br />
<br />
<Grid container>
<Grid item xs={6}>
<MultiSelect2
style={{ width: "80%" }}
id="Departments"
onChange={this.handleChangeField}
value={selectedOption}
/>
<label
id="departments"
style={{ visibility: "hidden", color: "red" }}
>
Select Applicable departments
</label>
</Grid>
As #sandeeppradhan you have to stop using these accessors, and think DATA driven ie change the states / props and display them through your interface, dont change styles as you are doing because the dom may change at anytime. And this is a source of bug as the component may not be attached to the dom or a child component may not be ready. Tbh, you are a bit too far in the wrong to make minor update to your code to fix the isssue
To answer more specifically to your question : probably the MultiSelect2 is not rendered when the event occurs.
Bad solution but may interest you : merge the MultiSelect2 inside Departments and use ref + state
ex : 
export class Departments extends Component {
constructor(props) {
super(props);
this.state={
departmentsStyle:{}
};
this.departmentsRef = React.createRef();
}
//...
continue = e => {
if (this.departmentsRef.current && this.departmentsRef.current.value.length < 1) {
this.setState({
departmentsStyle:{
border:"1px solid red",
visibility : "visible"
}
});
} else {
this.setState({
departmentsStyle:{}
});
e.preventDefault();
this.props.nextStep();
}
};
//.... ETC ETC
render() {
//...
return (
///...
//The ref is forwarded to the root element
//(if it does not work use inputRef={departmentsRef})
<Select ref={departmentsRef} style={this.state.departmentsStyle}
//...
)
}
Best solution I think : At this point the only think I would advice is if possible to look at Formik and transfer the FormikBag to the MultiSelect2. You could then manage better the components with the state of the form.
https://jaredpalmer.com/formik/docs/overview
good luck, all the best

Simple drag and drop with sorting without external library

I want to implement drag and drop of elements with sorting and I don't want to use any external library.
There will be 2 containers, I want to sort the elements within a container and drag/drop between the two containers. Any suggestions?
I've tried HTML5 and other things but didn't worked
In the above screen shot, I want to drag and drop the elements from shown to hidden and vice-versa, also sorting the elements among "Shown" row
/**
* Displays Dialog for Table show/hide columns
* #default {string} submitLabel, cancelLabel
* #default {bool} open
* #default {array} suggestions
*/
import React from "react";
import PropTypes from "prop-types";
import { withStyles } from "#material-ui/core/styles";
import SettingsIcon from "#material-ui/icons/Settings";
import IconButton from "#material-ui/core/IconButton";
import { theme } from "../../../../utilities/theme-default";
import HLTooltip from "../../../atoms/ToolTip";
import HLDialog from "../../../grouped/Dialog";
import HLSaveSettings from "../SaveTableSettings";
import HLTypography from "../../../atoms/Typography";
import HLChip from "#material-ui/core/Chip";
import * as colors from "../../../../utilities/color";
import Draggable from "react-draggable";
export const styles = () => ({
tableAction: {
width: "100%",
marginTop: `${theme.spacing.unit}px`
},
container: {
display: "flex"
},
title: {
flex: "0 0 auto"
},
section: {
border: `1px solid ${colors.neutralDark["120"]}`,
marginTop: `${theme.spacing.unit * 3}px`,
padding: `${theme.spacing.unit}px 0 ${theme.spacing.unit * 3}px ${theme
.spacing.unit * 6}px`,
display: "flex"
},
chipTextStyle: {
marginTop: `${theme.spacing.unit * 4}px`
},
chipStyle: {
padding: `${theme.spacing.unit * 3}px`,
marginTop: `${theme.spacing.unit}px`
},
dialogStyle: {
width: "500px"
},
defaultSection: {
marginTop: `${theme.spacing.unit * 2}px`
}
});
/**
* state component which handles table show/hide columns
*/
export class HLShowHide extends React.Component {
state = {
open: false,
headers: this.props.headers
};
/**
* function to display dialog for show/hide opetations
*/
dialogToggle = () => {
this.setState({
open: !this.state.open
});
};
onStart() {
this.setState({ activeDrags: this.state.activeDrags + 1 });
}
onStop() {
this.setState({ activeDrags: this.state.activeDrags - 1 });
}
onDragStart = (e, sectionIndex, index) => {
e.stopPropagation();
this.draggedItem = this.state.headers.sections[sectionIndex].items[index];
this.dragItemSection = sectionIndex;
this.dragItemIndex = index;
e.dataTransfer.effectAllowed = "move";
e.dataTransfer.setData("text/html", e.target.parentNode);
e.dataTransfer.setDragImage(e.target.parentNode, 20, 20);
};
onDragOver = (sectionIndex, index) => {
const draggedOverItem = this.state.headers.sections[sectionIndex].items[
index
];
// if the item is dragged over itself, ignore
if (this.draggedItem === draggedOverItem) {
return;
}
if (this.dragItemSection !== sectionIndex) {
var otherItems = this.state.headers.sections[this.dragItemSection].items;
otherItems.splice(this.dragItemIndex, 1);
}
// filter out the currently dragged item
let items = this.state.headers.sections[sectionIndex].items.filter(
item => item !== this.draggedItem
);
// add the dragged item after the dragged over item
items.splice(index, 0, this.draggedItem);
const sections = this.state.headers.sections;
sections[sectionIndex].items = items;
sections[this.dragItemSection].items = otherItems;
this.setState({ headers: { ...this.state.headers, sections } });
};
onDragOverSection = sectionIndex => {
if (this.state.headers.sections[sectionIndex].length === 0) {
var otherItems = this.state.headers.sections[this.dragItemSection].items;
otherItems.splice(this.dragItemIndex, 1);
let items = this.state.headers.sections[sectionIndex].items;
items.push(this.draggedItem);
const sections = this.state.headers.sections;
sections[this.dragItemSection].items = otherItems;
sections[sectionIndex].items = items;
this.setState({ headers: { ...this.state.headers, sections } });
}
};
onDragEnd = () => {
this.draggedIdx = null;
};
render() {
const { classes, submitLabel, cancelLabel } = this.props;
const { open, headers } = this.state;
const dragHandlers = {
onStart: this.onStart.bind(this),
onStop: this.onStop.bind(this)
};
const dialogBody = (
<div className={classes.dialogStyle}>
{headers.sections.map((section, sectionIndex) => (
<div className={classes.section}>
<span className={classes.chipTextStyle}>
<HLTypography
variant={
theme.palette.tableConstant.showHideColumn.sections.variant
}
color={
theme.palette.tableConstant.showHideColumn.sections.color
}
>
{section.label}
</HLTypography>
</span>
<span onDragOver={() => this.onDragOverSection(sectionIndex)}>
{section.items.map((item, itemIndex) => (
<div
className={classes.chipStyle}
key={item.value}
data-id={`${itemIndex}_${sectionIndex}`}
onDragOver={() => this.onDragOver(sectionIndex, itemIndex)}
>
<Draggable
onDrag={this.handleDrag.bind(this)}
{...dragHandlers}
>
<HLChip label={item.label} />
</Draggable>
</div>
))}
</span>
</div>
))}
<div className={classes.defaultSection}>
<HLSaveSettings
defaultLabel={headers.defaultLabel}
isDefault={headers.isDefault}
/>
</div>
</div>
);
return (
<React.Fragment>
{open && (
<div className={classes.container}>
<div className={classes.tableAction}>
<HLDialog
open={open}
submitLabel={submitLabel}
cancelLabel={cancelLabel}
bodyText={dialogBody}
maxWidth="xl"
onSubmit={() => {}}
onCancel={() => {
this.dialogToggle();
}}
/>
</div>
</div>
)}
{!open && (
<React.Fragment>
<HLTooltip title="Settings" placement="top">
<IconButton aria-label="Settings">
<SettingsIcon onClick={this.dialogToggle} />
</IconButton>
</HLTooltip>
</React.Fragment>
)}
</React.Fragment>
);
}
}
HLShowHide.propTypes = {
classes: PropTypes.object,
headers: PropTypes.arrayOf().isRequired,
open: PropTypes.bool,
submitLabel: PropTypes.string,
cancelLabel: PropTypes.string
};
HLShowHide.defaultProps = {
open: false,
submitLabel: "Set",
cancelLabel: "Cancel"
};
export default withStyles(styles)(HLShowHide);
my code which I tried
You can assign onDrop and onDrag events to div. You can hold each component in an array and when you drag you can remove the item from and array and when you drop, you can add this item to array. After that you can sort the array by array.sort()
<div onDrag={this.handleDrag()} onDrop={thishandleDrop()}>
handleDrag = () => {
//remove your item in array here
}
handleDrag = () => {
//add your item to array here
}

How to send props and methods between components?

Hi guys, I'm trying to code little app. I am trainee programmer. I need help to understand how to use props on my app. I'm currently using one component from CodePen and I fetched the data from jsonplaceholder. But I don't know how to pass props between this component and App.js. It was no problem with easier components but here is lot of methods and events. With this tagged input I want to add or delete items.
import React from "react";
import StateFullComponent from "./components/StateFullComponent";
import StatelessComponent from "./components/StatelessComponent";
import TagInput from "./components/TagInput";
function App() {
return (
<div>
<StatelessComponent
props1={"String"}
props2={1}
props3={true}
props4={JSON.stringify({ value: "value", key: 1 })}
/>
<StateFullComponent items={["apple", "orrange", "pear", "male"]} />
<TagInput />
</div>
);
}
export default App;
import React, { Component } from "react";
export default class TagInput extends Component {
constructor(props) {
super(props);
this.state = {
users: [],
focused: false,
input: ""
};
this.handleInputChange = this.handleInputChange.bind(this);
this.handleInputKeyDown = this.handleInputKeyDown.bind(this);
this.handleRemoveItem = this.handleRemoveItem.bind(this);
}
componentDidMount() {
fetch("https://jsonplaceholder.typicode.com/users")
.then(response => {
return response.json();
})
.then(result => {
this.setState({
users: result
});
});
}
add() {
let value = Math.floor(Math.random() * 10 + 1);
let users = this.state.users;
users.push(value);
this.setState({ users: users });
}
handleInputChange(evt) {
this.setState({ input: evt.target.value });
}
handleInputKeyDown(evt) {
if (evt.keyCode === 13) {
const { value } = evt.target;
this.setState(state => ({
users: [...state.users, value],
input: ""
}));
}
if (
this.state.users.length &&
evt.keyCode === 8 &&
!this.state.input.length
) {
this.setState(state => ({
users: state.users.slice(0, state.users.length - 1)
}));
}
}
handleRemoveItem(index) {
return () => {
this.setState(state => ({
users: state.users.filter((user, i) => i !== index)
}));
};
}
render() {
console.log(this.props, ":::::::::::");
const { users } = this.state;
const userId = users.map((user, id) => <li key={id}>{user.name}</li>);
const styles = {
container: {
border: "1px solid #ddd",
padding: "5px",
borderRadius: "5px"
},
items: {
display: "inline-block",
padding: "2px",
border: "1px solid blue",
fontFamily: "Helvetica, sans-serif",
borderRadius: "5px",
marginRight: "5px",
cursor: "pointer"
},
input: {
outline: "none",
border: "none",
fontSize: "14px",
fontFamily: "Helvetica, sans-serif"
}
};
return (
/* <div>
<ul>{userId}</ul>
<button onClick={this.handleRemoveItem().bind(this)}>add</button>
</div> */
<label>
<ul style={styles.container}>
{this.state.users.map((user, i) => (
<li
key={i}
style={styles.users}
onClick={this.handleRemoveItem(i).bind(this)}
>
{user}
<span>(x)</span>
</li>
))}
<input
style={styles.input}
value={this.state.input}
onChange={this.handleInputChange.bind(this)}
onKeyDown={this.handleInputKeyDown.bind(this)}
/>
</ul>
</label>
);
}
}
In your componentDidMount you are fetching data, and getting back an array of objects, and setting the state value users to the array of objects. That's all good and exactly what you should be doing.
The problem is in the render method when you are looping through the array of users. Remember that each user in the array is an object. Look at the jsx you have within the li element. You are rendering the user object, and an object is an invalid react child. Instead, you need to render the particular fields from the object.
Example, if the object contains a name field, and an email field, render {user.name} or {user.email}. That way you can render the particular fields of data from the user object.
<li
key={i}
style={styles.users}
onClick={this.handleRemoveItem(i).bind(this)}
>
Name: {user.name}
Email: {user.email}
Id: {user.id}
<span>(x)</span>
</li>
It seems you may still have some questions about passing props to a component. This only addresses the particular error you are seeing. If you still have questions let me know.

Resources