I'm trying to show lists of objects such as types and brands that I have in DyeStore my react app and after using map my app crashes but vs code doesn't tell about errors.
The following error occurs in these components:
const BrandBar = observer(() => {
const {dye} = useContext(Context)
return (
<Form className='d-flex'>
{dye.Brands.map(brand=>
<Card key={brand.id} className="mt-2" onClick={()=> dye.SetSelectedBrand(brand)} border={brand.id === dye.SetSelectedBrand.Id ? 'danger' : 'light'} style={{cursor:'poiinter'}}>
{brand.name}
</Card>
)}
</Form>
);
}
)
const TypeBar = observer(() => {
const {dye} = useContext(Context)
return (
<ListGroup>
{dye.Types.map( type =>
<ListGroup.Item
style={{cursor: 'pointer'}}
active = {type.id === dye.SetSelectedType.id }
onClick={() => dye.SetSelectedType(type)}
key={type.id}>
</ListGroup.Item>)}
</ListGroup>
);
}
)
This is the class where I store my brands and types arrays.
import { makeAutoObservable } from "mobx"
export default class DyeStore{
constructor(){
this._Types = [
{id:1,name:'Акриловая'}
]
this._Brands = [
{id:1,name:'Самсунг'}
]
this._Dyes = [
{id:1,name:'Самсунг',price: 2400,rating:5}
]
this._SelectedType = {}
this._SelectedBrand = {}
makeAutoObservable(this)
}
}
I also have setters and getters for DyeStore:
What errors I got:
I was trying to resolve this problem myself but most of the answers were not in the theme so.
Related
I am trying to add a className property to a newly created component like this:
const component = <Icons.RightArrowIcon /> // I want to add a className to this component
// Then...
// ...
return (
<>{component}</>
)
I wrote the following code:
type IconButtonProps = {
icon: 'RightArrowIcon' | 'WordIcon';
className?: string;
};
// eslint-disable-next-line react/display-name
const IconButton = React.forwardRef<any, IconButtonProps>((props, ref) => {
const getIcon = () => {
let icon: React.ReactNode | null = null
if (props.icon === 'RightArrowIcon') {
icon = <Icons.RightArrowIcon />
} else if (props.icon === 'WordIcon') {
icon = <Icons.WordIcon />
}
// This is what I thought it would be
if (icon !== null) { icon.props.className = styles.icon_button__icon }
return icon
}
return (
<div
ref={ref}
className={`${props.className} ${styles.icon_button__wrapper}`}
>
<button className={styles.icon_button}>
{getIcon()}
</button>
</div>
)
})
export default IconButton
But I got this error:
TypeError: Cannot add property className, object is not extensible
Not sure if it needs to be that complicated. Why not just render the icon conditionally?
return (
<div
ref={ref}
className={`${props.className} ${styles.icon_button__wrapper}`}
>
<button className={styles.icon_button}>
{
props.icon === 'RightArrowIcon'?//or any condition here
(
<Icons.RightArrowIcon className={style.anyClassHere}/>
):
(
<Icons.WordIcon className={style.anyClassHere}/>
)
}
</button>
</div>
)
I'm doing an e-commerce with React and I'm getting an error say
Cannot read properties of undefined (reading 'map')
Which doesn't make sense because I have done the same thing in another component and it works well.
Here is my code below with the comment on the map function that isn't working. Let me if something isn't clear. I've checked the syntax errors and all works fine
export class CartItem extends Component {
constructor(props) {
super(props);
this.state={
product: {},
failedToLoad: false
}
}
async componentWillMount(){
let data = await this.getProduct(this.props.product.itemId);
// let product = data.data.product;
// this.setState({product: product});
if (data.data.product) {
this.setState({product: data.data.product});
} else {
this.setState({failedToLoad: true});
}
}
async getProduct(id){
return await fetchTheQuery(
`query getProduct($id: String!){
product(id: $id){
name
prices{
currency
amount
}
}
}`, {id: id}
)
}
render() {
const {addProduct, productsToPurchase} = this.props.cartContext
const {selectedCurrency} = this.props.currencyContext
console.log(this.state.product.prices)
let productFetched = this.state.product
if (this.state.failedToLoad){
return (<div>Something went wrong</div>)
}
else if (productFetched){
return(
<div>
<h2> {this.state.product.name} </h2>
<h5>
{/*There is an error here*/}
{ this.state.product.prices.map(
price =>{
if (price.currency == selectedCurrency){
return( <> { getSymbolFromCurrency(selectedCurrency) +" "+ price.amount }</> )
}
}
)}
</h5>
<button onClick={() => {
addProduct(this.props.product.itemId, this.state.product.prices)
}}> Add </button>
<h4>{productsToPurchase[this.props.itemIndex].qty}</h4>
<hr/>
</div>
)
}
else {
return <p>Loading............</p>
}
}
}
You need to check if the this.state.product.prices exists in the object.
You are getting this error since the collection is empty during the first render.
{ this.state.product.prices
&& this.state.product.prices.map(
price =>{
if (price.currency == selectedCurrency){
return(
<>
{
getSymbolFromCurrency(selectedCurrency) +" "+ price.amount }.
</> )
}
}
)}
I started my learning path few months ago (html, css, js) and I have a question for an issue that I have with react (just started learning it).
I have an error that says : data.map is not a function
I want to loop trough my array of objects with map, and dispatch the props (title, answer) to the child for each loop, to make a list of different FaqComponent having each the {title and answer}
const data = useSelector(state => ({
...state.homePage.list
}))
console.log(data);
return (
<div>
{data.map((title, answer) => (
<FaqComponent
title={title}
answer={answer}
/>
))}
</div>
);
}
export default ...;
Thanks for your replies
You're using an object {} instead of an array [] syntax.
Try with:
const data = useSelector(state => ([
...state.homePage.list
]));
You should declare "data"s type, if it is an array so your function should be like :
const data = useSelector(state => ([
...state.homePage.list
]))
console.log(data);
return (
<div>
{(data && data.length > 0) ? data.map((item, i) => (
<FaqComponent
title={item.title}
answer={item.answer}
key={i}
/>))
: <div>No Result!...</div>}
</div>
);
}
export default ...;
Hi I am making a website building app that uses styled components and forms to render data into sections of a page. So I decided all of my styled components will be default exports then imported to a context and then loaded into the form when its opened. Then from a select menu the user gets a map of all the possible components to render and when an option is selected a string reference filters the component array down to the called function and then adds all the other data and then displays it on screen. When I launch I get this error: "React.jsx: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: < BurgerMenu / >. Did you accidentally export a JSX literal instead of a component?"
Here are all of the parts:
BurgerMenu.js
import React, { useState, useRef } from "react";
import { ThemeProvider } from "styled-components";
import { useOnClickOutside } from "../../state/useOnClickOutside";
import { GlobalStyles } from "../../state/globals";
import { useTheme } from "../../state/useTheme";
import Hamburger from "./Hamburger";
import Menu from "./Menu";
const BurgerMenu = () => {
const [open, setOpen] = useState(false);
const node = useRef();
useOnClickOutside(node, () => setOpen(false));
const { theme } = useTheme();
return (
<ThemeProvider theme={theme}>
<>
<GlobalStyles />
<div ref={node}>
<Hamburger open={open} setOpen={setOpen} />
<Menu open={open} setOpen={setOpen} />
</div>
</>
</ThemeProvider>
);
};
export default BurgerMenu;
Component Context:
import BurgerMenu from "../header/Hamburger/BurgerMenu";
const components = [{
name: "BurgerMenu",
func: BurgerMenu,
els: ["a", "a", "a", "a", "a", "a"],
}]
Site Form (where the component context is called)
const { components } = useComponentContext();
const [mount, setMount] = useState('')
<select name='component' onChange={(e) => setMount(e.target.value)}>
{components.map((component) => (
<option key={component.name} value={component.name}>
{component.name}
</option>
))}
</select>
<button
className='btn primary btn-block'
onClick={() => {
convertStringToComponent(mount);
setTimeout(setLoaded((prevState) => !prevState),2000)}}>
Add Component
</button>
Function convertStringToComponent
const convertStringToComponent = (mount, compStyle) => {
const ComponentName = components
.filter((comp) => comp.name === mount)
.map(({ func }) => func)[0];
return (
<ComponentName
content={content}
font={font}
pallet={pallet}
h={h}
icon={icon}
p={p}
vid={vid}
img={img}
a={a}
li={li}
button={button}></ComponentName>
);
};
const VariableComponent = convertStringToComponent(mount);
this is then called in a different component with
{loaded === true && <VariableComponent />}
Any help would be great!
The issue is with how you are using convertStringToComponent's function reeturn valaue.
When you call, convertStringToComponent you are returned an instance of component which is
<ComponentName
content={content}
font={font}
pallet={pallet}
h={h}
icon={icon}
p={p}
vid={vid}
img={img}
a={a}
li={li}
button={button}></ComponentName>
Now when rendering you are trying to again create an instance eout of this by using it as
{loaded === true && <VariableComponent />}
instead of
{loaded === true && VariableComponent}
However, there is another issue, when you call convertStringToComponent you shouldn't try to store the result in a variable and export it, instead you should be storing it in instance state and render it.
A better way to structure your code would be
export const convertStringToComponent = (mount, compStyle) => {
const ComponentName = components
.filter((comp) => comp.name === mount)
.map(({ func }) => func)[0];
return (otherProps) => (
<ComponentName
{...otherProps}
content={content}
font={font}
pallet={pallet}
h={h}
icon={icon}
p={p}
vid={vid}
img={img}
a={a}
li={li}
button={button}></ComponentName>
);
};
Now you can use it like
const [VariableComponent, setVariableComponent] = useState(null);
<button
className='btn primary btn-block'
onClick={() => {
const comp = convertStringToComponent(mount);
setVariableComponent(comp);
setTimeout(setLoaded((prevState) => !prevState),2000)}}>
Add Component
</button>
{isLoaded && <VariableComponent />}
I'm learning ReactJS and using this library https://github.com/salesforce/design-system-react.
I'm attempting to use a component I created SelectCell. It's being used two times. I'd like to pass it a prop selectedOption and in the first instance pass it a property originating from my state, a property selectedSectionId and the second time the component is used set selectedOption to be selectedQuestionId.
The issue is the library obfuscates some of the logic away and I'm not well versed enough in react to understand what to do. I set items on the DataTable component and I know the children components have access to item in props. I'm getting the error TypeError: Cannot read property 'selectedSectionId' of undefined My component is below:
import React from 'react';
import {Button,DataTable,DataTableColumn,DataTableCell,Dropdown,DataTableRowActions} from '#salesforce/design-system-react';
const ParameterDataTableCell = ({ children, ...props }) => (
<DataTableCell title={children} {...props}>
<input type='text' className='slds-input' value={props.item.parameterName} />
</DataTableCell>
);
ParameterDataTableCell.displayName = DataTableCell.displayName;
const SelectCell = ({ children,...props }) => (
<DataTableCell {...props}>
<div>
<Dropdown
align='left'
checkmark={false}
iconCategory='utility'
iconName='down'
iconPosition='right'
label={setPicklistLabel(props.allOptions,props.type,props.item,props.selectedOptionId)}
options={props.allOptions}
value={props.item.sectionName}>
</Dropdown>
</div>
</DataTableCell>
);
const setPicklistLabel = (allOptions,picklistType,item,selectedOptionId) => {
const foundOption = allOptions.find((thisOption) => selectedOptionId===thisOption.id);
return foundOption ? foundOption.label : 'Select an Option';
}
SelectCell.displayName = DataTableCell.displayName;
class ParameterTable extends React.Component {
static displayName = 'ParameterTable';
state = {
paramRows: [
{
parameterName: 'param1',
selectedSectionId: '001441094',
selectedQuestionId: '00ri23or231441094'
},
{
parameterName: 'param2',
selectedSectionId: '001441094',
selectedQuestionId: '00ri23or231441094'
}
],
};
addRow = () => {
const newRow = {'parameterName':'','selectedSectionId':'','selectedQuestionId':''};
const rows = this.state.paramRows;
rows.push(newRow);
this.setState({items:rows});
};
render() {
return (
<div>
<DataTable
items={this.state.paramRows}
className='slds-m-top_large'
>
<DataTableColumn
label='Parameter Name'
primaryColumn
property='parameterName'
>
<ParameterDataTableCell />
</DataTableColumn>
<DataTableColumn
label='Section Name'
property='sectionName'
>
<SelectCell
allOptions={this.props.serverData.allSections}
selectedOptionId={this.props.item.selectedSectionId}/>
</DataTableColumn>
<DataTableColumn
label='Question Name'
property='questionName'
>
<SelectCell
allOptions={this.props.serverData.allQuestions}
selectedOptionId={this.props.item.selectedQuestionId}/>
</DataTableColumn>
</DataTable>
<Button
iconCategory='utility'
iconName='add'
iconPosition='right'
label='Add Parameter'
onClick={this.addRow}
/>
</div>
);
}
}
export default ParameterTable;
Well, from first glance, it seems like you missed out using the constructor(props) and super(props) lines.
class ParameterTable extends React.Component {
static displayName = 'ParameterTable';
constructor(props) {
super(props);
this.state = {
paramRows: [
{
parameterName: 'param1',
selectedSectionId: '001441094',
selectedQuestionId: '00ri23or231441094'
},
{
parameterName: 'param2',
selectedSectionId: '001441094',
selectedQuestionId: '00ri23or231441094'
}
],
};
}