ReactJS: How to map items in conditional statements - reactjs

I have a react component that allows a user to click a button in the header and add different input types.
export default class ElementContainer extends Component {
render() {
return (
<div className="append-header">
<Headline buttonCheck={this.props.buttonCheck} />
<SubHeadline buttonCheck={this.props.buttonCheck} />
<URLButton={this.props.buttonCheck} />
</div>
)
}
}
I'm trying to implement react-beautiful-dnd into the project so that those inputs can be repositioned like a list in Trello.
Looking at that library (and other similar libraries), they use the data as lists in order to perform the drag and drop function.
The items in my app are added to the view by conditional rendering:
export default class InputShow extends Component {
render() {
const { node } = this.props;
return (
<div className="editor-div" >
{
(node.type === 'buttonA') ?
<textarea
//omitted code
id={node.id}
onChange={this.props.inputContentHandler} />
:
(node.type === 'buttonB')
?
<URLButton
url={this.url}
id={node.id}
title={this.title}
/>
:
""
}
</div >
)
}
}
I've tried to map the items by creating a state for items (additions)
export default class InputShow extends Component {
constructor(props) {
super(props)
this.state = {
additions: []
}
}
render() {
const { node } = this.props;
return (
<div className="editor-div" >
{this.state.additions.map(addition => (
<div key={addition.id}>
{
(node.type === 'buttonA') ?
<textarea
//omitted code
id={node.id}
onChange={this.props.inputContentHandler} />
:
(node.type === 'buttonB')
?
<URLButton
url={this.url}
id={node.id}
title={this.title}
/>
:
""
}
</div>
))}
</div >
)
}
}
I didn't get any errors, however now when I click on the buttons, no data is being displayed in the view. I've done simple maps in the past with API and local data but I've never tried it with ternary statements. Thanks for any feedback on a solution to this problem.

What you can do is separate the view logic from the code and create a functional component. Pass the values from the main as below:
{this.state.additions.map(addition => (
return <CustomTemplate id={addition.id}
nodeId={node.id} changeEvent={this.props.inputContentHandler}
nodeType={node.Type} url={this.url} title={this.title}/>))}
Create CustomTemplate something like this
const CustomeTemplate =(props)=>(
use props to get the values in the templates
)

Related

How to add conditional statement inside react fragment

Inside of the react fragment I have to add conditional statement. On basis of the conditional statement, return what expected
return (
<React.Fragment>
<Toolbar
pageTitle={i18next.t('TITLE')}
iconButtons={this.state.icons}
{this.props.abc && this.props.abc.operation ?(
moreButton={moreButton}
):null}
/>
if this.props.abc.operation is present then only show morebutton if not show only iconbuttons this is my condition and above is the code i tried. any help would be really appreciated.
<>
<Toolbar
pageTitle={i18next.t('TITLE')}
iconButtons={this.state.icons}
moreButton={this.props.abc && this.props.abc.operation && moreButton}
/>
</>
Try to use this.
Instead of conditional rendering you can do like below.
isAbcOperationExist = (args) => {
if(args && args.operation){
return true;
}
return false;
}
Now inside component props:
<Toolbar
pageTitle={i18next.t('TITLE')}
iconButtons={this.state.icons}
showMoreButton={() => this.isAbcOperationExist(this.props.abc)}
/>
Based on result returned boolean value by method isAbcOperationExist you can show or hide moreButton
More Example:
Assumption this is class based component:
class YourComponent extends React.Component {
constructor(props){
super(props)
}
isAbcOperationExist = (args) => {
if(args && args.operation) {
return true;
}
return false;
}
render (){
return (
<Toolbar
pageTitle={i18next.t('TITLE')}
iconButtons={this.state.icons}
moreButton={moreButton}
showMoreButton={() => this.isAbcOperationExist(this.props.abc)}
/>
)
}
}
For Toolbar Component assuming it as functional base component:
const Toolbar = ({pageTitle, iconButtons, showMoreButton, moreButton}) => {
return(
<div>
{
showMoreButton ? <button onClick={moreButton}>Show More</button> : null
}
</div>
)
}
React Fragment has nothing to do with this. You also can't manipulate component props like this. The idea would be to have a single prop for iconButtons and moreButton and and do the logic what to show inside Toolbar component

How to show a block of collapsible text on click of button

I am trying to implement a collapsible component. I have designed it such as, on click of a button, a block of dynamic text will appear. I made a functional component and using the tags in a class. The name of the component is, CustomAccordion.jsx and using this component in Container.jsx
I have tried to create a button and a function for onClick event.
Part of the CustonAccordion.jsx
const handleToggle = () : string =>{
let content = this.nextElementSibling;
if (content.style.maxHeight){
content.style.maxHeight = null;
}else{
content.style.maxHeight = content.scrollHeight +'px';
}
}
export default function CustomAccordion(props: PropType): React.Component<*> {
const { title, children } = props
return(
<div>
<AccordionButton onClick={() => this.handleToggle()}>{title}</AccordionButton>
<AccordionContent>
<p>{children}
</p>
</AccordionContent>
</div>
)
}
Part of calling Container.jsx
<CustomAccordion title = {this.props.name}>
<p>This is the text passed to component.</p>
</CustomAccordion>
<br />
This does not show the expanded text and it seems that the click event does not work properly. I am very new in react, guessing the syntax might be incorrect.
In react you should generally try to avoid touching DOM directly unless you really have to.
Also you are accessing the handleToggle function wrongly. It should be onClick={() => handleToggle()} because this in your case is window/null and so it has no handleToggle method.
Instead you can use a stateful class component to achieve the same thing.
export default class CustomAccordion extends React.Component {
state = {show: false};
toggle = () => this.setState({show: !this.state.show});
render() {
const {title, children} = this.props;
const {show} = this.state;
return (
<div>
<AccordionButton onClick={this.toggle}>{title}</AccordionButton>
{show && (
<AccordionContent>
<p>{children}</p>
</AccordionContent>
)}
</div>
)
}
}
If you want to have some kind of animation, you can set different className based on the show state instead of adding/removing the elements.

How to hide TagNav in profile page in reactioncommerce

In reactionCommerce I want to hide TagNav in Navbar in profile component/page based on some condition. I am new into reactionCommerce
You need to override TagNav using Reaction Commerce's Component API.
Since you only want to customize the way the component is rendered, I suggest using getRawComponent to get Reaction's default TagNav component without its HOCs, then extending it and replacing it using replaceComponent.
import React from "react";
import { Components, getRawComponent, replaceComponent } from "#reactioncommerce/reaction-components";
const TagNav = getRawComponent("TagNav");
class CustomTagNav extends TagNav {
/**
* This implementation of render will override TagNav's default
*/
render() {
const { navbarOrientation, navbarPosition, navbarAnchor, navbarVisibility } = this.props;
// Provided that you want to return a whole different component tree if your condition matches
if (yourCondition) {
return (
{/* What you want to return if TagNav isn't shown */}
);
}
return (
<div className={`rui tagnav ${navbarOrientation} ${navbarPosition} ${navbarAnchor} ${navbarVisibility}`}>
<div className="navbar-header">
<Components.Button
primary={true}
icon="times"
status="default"
className="close-button"
onClick={this.props.closeNavbar}
/>
{this.props.children}
</div>
{this.renderShopSelect()}
<div className="navbar-items">
<Components.DragDropProvider>
<Components.TagList
{...this.props}
isTagNav={true}
draggable={true}
enableNewTagForm={true}
>
<div className="dropdown-container">
<Components.TagGroup
{...this.props}
editable={this.props.editable === true}
tagGroupProps={this.tagGroupProps(this.state.selectedTag || {})}
onMove={this.props.onMoveTag}
onTagInputBlur={this.handleTagSave}
onTagMouseOut={this.handleTagMouseOut}
onTagMouseOver={this.handleTagMouseOver}
onTagSave={this.handleTagSave}
/>
</div>
</Components.TagList>
</Components.DragDropProvider>
{this.props.canEdit && this.renderEditButton()}
</div>
</div>
);
}
}
replaceComponent("TagNav", CustomTagNav);

React content rendering based on map output not working

I have a component which is going to rely on the results of an array.map to determine it's output. In this case the array contains an element called "name", and one of the names is 'Welcome.' What needs to happen is the component spits out a particular div for the 'Welcome' instance and different content (an Accordion component) for every other instance. I've used a ternary operator in the render which I'm then calling in the return, but it's outputting the same text for every instance of the component (the text specified for only the 'Welcome' instance.) I can't for the life of me figure out what I'm doing wrong. Here's the code:
export default class Back extends React.Component {
constructor(props) {
super(props)
}
render() {
const CheckDomains = this.props.totaldomains.map((domain, index) => {
<div>
{
domain.name === 'Welcome' ?
<div>This is welcome text.</div>
:
<div>This is accordion text.</div>
}
</div>
)
});
return(
<div className='back'>
{CheckDomains}
</div>
);
}
}
You need to return something in your map callback function.
Like so:
const CheckDomains = this.props.totaldomains.map((domain, index) => {
return (
<div>
{
domain.name === 'Welcome' ?
<div>This is welcome text.</div>
:
<div>This is accordion text.</div>
}
</div>
)
});

User react router inside of map

I would like to use react-router (must use 2.8.1) for rendering content inside a list (using map).
However, if I display {this.props.children} outside the .map, it renders one at time.
I need it to display inline/under the list entry.
How can I achieve this?
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
movies: x.movies
};
}
render() {
return (
<div>
<h2>Repos</h2>
{x.movies.map(movie =>
<span key={movie.id}>
{movie.name}
<NavLink to={"/repos/" + movie.id + "/next"}>React Router</NavLink>
</span>
)}
{this.props.children}
</div>
);
}
}
You are rendering the children inside the loop, which i believe is causing the extra Next Id:4 to be displayed between each entry.
Try the below, by rendering the children outside the loop.
{
x.movies.map(movie => (
<span>
<Result key={movie.id} result= {movie}/>
</span>
))
}
<span>{this.props.children}</span>

Resources