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
Related
Using React JSX, I have an array levels which can contain arrays of one or more of the levels with a name, for example: one, two and three. In my render function I can call {renderLevels} which renders all levels separated by a comma.
This works:
const renderLevels = levels.map((item, index) => {
return (
<Fragment key={index}>
{(index ? ' & ' : '')} {item.name}
</Fragment>
)
}
);
In case all levels are present I want to render 'all levels', instead of the comma separated list. In all other cases I want the list. So I change my code.
This does not work:
const renderLevels = () => {
if (levels.length === 3) {
return (
'all levels'
)
}
levels.map((item, index) => {
return (
<Fragment key={index}>
{(index ? ' & ' : '')} {item.name}
</Fragment>
)
}
)
};
My const is now a function I then call with {renderLevels()}. The problem: the list of item names is no longer returned when there are fewer than 3 levels. My if-statement works and console.log(item.name) inside .map does show me the results in case there are fewer than 3 levels. Getting the return values however does not. What am I doing wrong?
You are missing return for the levels.map(). Currently, you are just returning for the function, inside the if block but you have not returned anything when that if is not executed.
const renderLevels = () => {
if (levels.length === 3) {
return (
'all levels'
)
}
return levels.map((item, index) => {
return (
<Fragment key={index}>
{(index ? ' & ' : '')} {item.name}
</Fragment>
)
}
)
};
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.
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.
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>
);
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>
)
}