React not executing block of switch statement? - javascript

I have a product component that renders n number of sections. The code in the product component:
let sections = this.state.product.sections.map((section, idx) => {
return (
<Section sectionType={section.id} section={section} />
)
})
return (
<div>
{this.state.product.name}
{sections}
</div>
)
The code in the section component:
renderSection() {
switch (this.props.sectionType) {
case 'heroImage':
return (
<img src={image.url} />
)
case 'doublePane':
this.props.section.items.map((item, idx) => {
console.log(item.id);
if (1 === 1) {
return (
<div>hi</div>
)
}
})
default:
return (
<div>hey there</div>
)
}
}
render() {
return (
<div>
{this.renderSection()}
</div>
)
}
I added the 1===1 line just to make sure it would execute, but the output of my code is still
the heroImage case properly executes
the console log of item.id happens (so we definitely enter the doublePane block), but the code inside of the 1===1 block does not execute.
Any idea what's happening here to not allow me to run the code inside of the 1===1? Thanks in advance!

You need to return the result of the mapping function, in addition to returning within the mapping function:
renderSection() {
switch (this.props.sectionType) {
case 'heroImage':
return (
<img src={image.url} />
);
case 'setOfTwo':
return (
<div>
{this.props.section.items.map((item, idx) => {
console.log(item.id);
return (
<div>hi</div>
);
})}
</div>
);
default:
return (
<div>hey there</div>
)
}
}
Wrapping the return value in a div isn't necessarily required, but I prefer to return a consistent item (in this case a single JSX element) from functions.

Related

How to use ternary condition to render jsx using react?

i want to return jsx if some condition is true if not undefined should be returned.
below is my code,
const showInfo = (item) {
return (
<div>
<div>
<span>name</span>
</div>
<div>
<button>click</button>
</div>
</div>
);
}
const Parent = () => {
return (
<Child
onDone = {({item}) => {
notify ({
actions: (condition === 'value1' || condition === 'value2' ) &&
showInfo(item) //should put this condition into showInfo method
})
}}
/>
);
}
what i am trying to do?
the above code works. but now i want to put the condition inside the showInfo method. so if condition is true return jsx and if condition is false should return undefined.
what i have tried?
I have tried something like below
const showInfo = (item) {
return
{(condition === 'value1' || condition === 'value2' ) ? <div>
<div>
<span>name</span>
</div>
<div>
<button>click</button>
</div>
</div>
: undefined
}
);
}
const Parent = () => {
return (
<Child
onDone = {({item}) => {
notify ({
actions: showInfo(item) //error here
})
}}
/>
);
}
but the above tried code, gives error "Type 'void' is not assignable to type 'ReactNode'" at actions statement.
could someone help me with this. i am not sure if i have used ternary operator properly. thanks.
EDIT
after trying one of the answers provided,
notify is a method that is returned from usehook
and it evaluates to the component below
const Something: React.FC<SomethingProps> = ({
description,
actions,
...props
}) =>
(
<Header>
<Title>{title}</Title>
</Header>
{(description ||actions) && (
<Body> //this is displayed
{description && <Description>{description}</Description>}
{actions && <Actions>{actions}</Actions>}
</Body>
)}
);
here the component is displayed when the condition fails in showInfo component.
in showInfo i am returning undefined if condition fails but still in the Something component the is displayed even though i have {description || actions}
i am not sure what is happening here.what is the condition i have to check for actions to not display in this case
i have tried
{(description ||actions !== 'false') && (
<Body> //this is displayed
{description && <Description>{description}</Description>}
{actions && <Actions>{actions}</Actions>}
</Body>
)}
and this works. i am wondering why i should specifically mention
actions !== 'false'
instead of actions only
could someone help me with this. thanks.
If you want to return jsx from function you should wrap them inside some component. In this case you cen use <React.Fragment> or just <>. Another problem which I can see is that you probably forgot about arrow in you arrow function. Also don't know from where variable names condition comes from.
const showInfo = (item) => {
return (
<>
{ condition === "value1" || condition === "value2" ? (
<div>
<div>
<span>name</span>
</div>
<div>
<button>click</button>
</div>
</div>
) : undefined}
</>
);
};
Wouldn't it be better to use the useState or useEffect hooks?

How to handle a generated big form in React Js

I trying to generate a big form based on what I get from the server.
sometimes I generate 32 elements sometimes 57 or 4 I don't know.
I try to create a component for each type of element like select, text, number, textarea and so on.
each component passes the value to the parent component and setState the value to the parent.
imagine I have 20 inputs and custom select-option elements.
when I type something in one of the inputs characters show up after 2seconeds and there is a huge lag in my component.
I know because of the setState method my hole component (I mean my parent component or my single source of truth) re-renders and causes the problem.
in fact, I don't know other ways.
I try to use a "this.VARIABLE" and instead of setState, I update the "this.VARIABLE" and problem solved. but I need my state.
any help or solution?
my code (parent Component, source of truth ):
// ---> find my component based on the type that I get from server
findComponent ( item , index) {
if ( item.type === 'text' || item.type === 'number') {
return (<Text data={item} getUpdated={this.fetchingComponentData} />);
} else if ( item.type === 'longtext') {
return (<Textarea data={item} getUpdated={this.fetchingComponentData} />);
} else if ( item.type === 'select' ) {
return (<SelectOption data={item} getUpdated={this.fetchingComponentData} />);
} else if ( item.type === 'autocomplete') {
return (<AutoTag data={item} url={URL1} getUpdated={this.fetchingComponentData} />);
} else if ( item.type === 'checkbox_comment' ) {
return (<CheckboxComment data={item} getUpdated={this.fetchingComponentData} />);
} else if ( item.type === 'multiselect' ) {
return (<Multiselect data={item} getUpdated={this.fetchingComponentData} />);
} else {
return (<p>THERE IS NO TYPE OF => {item.type}</p>);
}
}
// ----> if i setState here ==> big lag
fetchingComponentData(OBJ) {
let index = null;
// let Answer = [...this.state.Answer];
index = Helper.find_item(this.Answer , OBJ , 'unique_key');
if ( index === -1 ) {
this.Answer.push(OBJ);
} else {
this.Answer[index].value = OBJ.value;
}
}
// ----> in my render method
render () {
return (
<React.Fragment>
<div className="row Technical section" data-info="Technical">
<div className="col-6">
{data.map( (item,index) => {
return (
<React.Fragment key={index}>
<div className="rowi">
{item.attributes.map( (item, index)=> {
return <React.Fragment key={index}>{this.findComponent(item, index)}</React.Fragment>;
})}
</div>
</React.Fragment>
)
})}
</div>
<div className="col-6"></div>
</div>
</React.Fragment>
);
}
Have you tried to make an object out of your components and pass it to setState at once?
const nextState = componentList.map(component => {
return {[component]: value};
});
this.setState({...nextState});
Edit: Okay i got another part you could do better.
You should build an array with you components in componentWillMount function instead of fetching all the data inside the render. Like you said, it's updating everytime any state changes, and all the components are also updating with the parent.
This is to be made in addition with what I suggested before, but it is of far more importance because of the impact on the ressource.

React: rendering components in a loop

All the docs for map use braces but the code below and most examples I see when dealing with React use parenthesis. I'm trying to figure out exactly what the difference is and what the code is doing.
When using braces, nothing renders unless I specifically add return. So my take is that the parenthesis act as some sort of inline function that automatically returns or React converts the result and inlines it into the JSX?
// Renders fine
render()
{
return (
<div className="item-list">
{
this.props.items.map(
( _item, _index ) => (
<ItemComponent
key={ _index }
name={ _item.name }
description={ _item.description }
/>
) )
}
</div>
);
}
// Nothing
render()
{
return (
<div className="item-list">
{
this.props.items.map(
( _item, _index ) =>
{
<ItemComponent
key={ _index }
name={ _item.name }
description={ _item.description }
/>
} )
}
</div>
);
}
// Renders fine
render()
{
return (
<div className="item-list">
{
this.props.items.map(
( _item, _index ) =>
{
return <ItemComponent
key={ _index }
name={ _item.name }
description={ _item.description }
/>
} )
}
</div>
);
}
Nothing to do with React, It is all about javascript
Curly braces saying it is a function body so we need to manually use return keyword
this.props.items.map(
( _item, _index ) =>
{ // Note: represent function body, normal javascript function
<ItemComponent
key={ _index }
name={ _item.name }
description={ _item.description }
/>
} )
According to arrow functions, has implicit return behavior hence so need to mention explicitly if single line expression.
render()
{
return (
<div className="item-list">
{
this.props.items.map(
( _item, _index ) => ( // Note: single line expression, so impilicit;y return our ItemComponent
<ItemComponent
key={ _index }
name={ _item.name }
description={ _item.description }
/>
) )
}
</div>
);
}
So parenthesis in an arrow function returns a single value, the curly braces are used when executing multiple lines of code and not just a simple return, so a manual return statement is required just because javascript can't know what among those lines to return.
materials.map(material => ({key:material.name}));
return an object
materials.map(material => {
let newMat = material.name+'_new';
return newMat;
});
we need to return since we are doing 1 or many lines of manipulation and trying to return end result

Return nothing using React render

I have render in React component. If a condition is fulfilled I want to do something, in this case to show a message when hover over an icon but otherwise I don't want it to do anything.
I tried with an if condition but it doesn't work. This is my code:
render() {
const text= this.checkSomething();
return (
{
if (text.length > 0) {
<ActionBar>
<div>
<Icon type="..."/>
//do something here
</div>
</ActionBar>
}
}
But I get the following error:
A valid React element (or null) must be returned. You may have
returned undefined, an array or some other invalid object.
I know that I return something that doesn' exist if text.length == 0, but is there any way to make it work, like don't return anything if the condition is not met?
You cannot have an if within the return of the render() function. Only ternary and short-circuit operations will work inside the return.
It's best to perform as much logic before your return.
Try this instead:
render() {
const text= this.checkSomething();
if(!text.length) return null;
return (
<ActionBar>
<div>
<Icon type="..."/>
//do something here
</div>
</ActionBar>
);
}
}
In render, you need to return either a React.Element or null, so the shortest way could be like:
render() {
const text = this.checkSomething();
return (
text.length > 0 ? (
<ActionBar>
<div>
<Icon type="..."/>
//do something here
</div>
</ActionBar>
) : null
);
}
Read more about this here: https://facebook.github.io/react/docs/react-dom.html#render
You are not returning the Component. Try this code:
render()
{
const text = this.checkSomething();
if (text.length > 0) {
return ( <ActionBar>
<div>
<Icon type="..."/>
//do something here
</div>
</ActionBar> )
} else {
return null;
}
}
You are on the right path. Just a little mistake. You should condition it like so:
render() {
const text= this.checkSomething();
if (text.length > 0) {
return (
<div>
// do something
</div>
);
}
// if condition is not met
return (
<div>
<h1>please wait while data is loading..</h1>
</div>
);
}
Its simple check for condition and return component or just null
render() {
const text= this.checkSomething();
if (text.length > 0) {
return <ActionBar>
<div>
<Icon type="..."/>
</div>
</ActionBar>
}else{
return null
}
}
Here is working example.
class App extends React.Component {
construct() {
//...
}
sometext() {
return '123213';
}
render() {
return(
<div>
{(this.sometext().length > 0) ? <ActionBar /> : null}
</div>
);
}
}
const ActionBar = () => (
<div>Super</div>
)
ReactDOM.render(
<App />,
document.getElementById('root')
);
<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="root"></div>
You can wrap it in a function and then call itself, all within the return.
return (
<div>
{(() => {
if (catSay == "maow") return <p>meow</p>;
})()}
</div>
);

Map iterator undefined React.JS

I'm trying to render a list, but when I try and map over the list I can not access each individual element, because I ReferenceError saying that 'e' is undefined. Am I writing this correctly?
render() {
return (
<div>
{console.log(Object.keys(this.props.emojis))} --> Returns the correct list
Object.keys(this.props.emojis).map(e => (
{console.log("EMOJI: ",e)}
<Emoji emote={e} />
))
</div>
)
}
Write it like this, it will work:
render() {
return (
<div>
{
Object.keys(this.props.emojis).map((e,i) => {
console.log("EMOJI: ",e);
return <Emoji key={i} emote={e}/>
})
}
</div>
)
}
Changes:
You are already inside a map function, so no need to use {} for console.log.
You are using () with map function and inside () you are using 2 statement, that is not allowed with (), if you want to do some calculation always use {}, and return something inside it.
Suggestion: Always assign key whenever creating the ui items dynamically.
Let me know if you need any help.
See if this work for you.
logging(e) {
console.log("EMOJI: ", e);
}
render() {
return (
<div>
Object.keys(this.props.emojis).map(e => (
this.logging(e);
<Emoji emote={e} />
))
</div>
)
}

Categories

Resources