React content rendering based on map output not working - reactjs

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>
)
});

Related

ReactJS: How to map items in conditional statements

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
)

Is there any obvious reason this won't render?

I'm pulling in an array of objects and mapping them to another component to be rendered.
renderRatings(){
if(this.props.ratings.length > 0){
return this.props.ratings.map(rating => {
<Rating
id={rating.id}
title={rating.title}
value={rating.value}
/>
});
}
}
This is where I render the rendering function.
render() {
return (
<div>
{this.renderRatings()}
</div>
);
}
}
This is the component I'm trying to populate and have rendered.
class Rating extends Component{
componentDidMount(){
console.log("props equal:", this.props)
}
render() {
return (
<div className="card darken-1" key={this.props._id}>
<div className="card-content">
<span className="card-title">{this.props.title}</span>
<p>{this.props.value}</p>
<button>Edit</button>
<button onClick={() => this.deleteRating(this.props._id)}>Delete</button>
</div>
</div>
);
}
}
export default connect({ deleteRating })(Rating);
No errors are being thrown, but when the page loads, the surrounding menu comes up, and the fetch request returns an array and supposedly maps it to the 'Rating' component, but no mapped Rating cards appear.
in your map, you're not returning the Rating etc... because you used { to define a code block, you have to type return. And since it's multi-line, use parens to mark the start and end of the Rating component.
return this.props.ratings.map(rating => {
<Rating
id={rating.id}
title={rating.title}
value={rating.value}
/>
needs to be
return this.props.ratings.map(rating => {
return (<Rating
id={rating.id}
title={rating.title}
value={rating.value}
/>)

My react component is rendering 1 too many child components

I'm new to react and struggling with working on why this is happening
I have a component, which takes an array, maps it and then for each element it renders a new component
class CallingPattern extends Component {
constructor(props) {
super(props);
const { serviceId } = this.props.match.params
this.state = {
serviceId: serviceId,
}
}
render() {
return (
<div>
<h1>CallingPattern page</h1>
<h4>Current Journey ServiceID: {this.state.serviceId}</h4>
<CallingStation serviceId={this.state.serviceId}/>
<div className="calling-stations">
// journeyData is a local JSON file
{journeyData.service.stops.map((stop, i) => {
{console.log("mapping")} // logs 8 times (length of array)
return (
<CallingStation
key={`station-${i}`}
stopInfo={stop}
serviceId={this.state.serviceId}
/>
);
})}
</div>
</div>
);
}
}
export default CallingPattern;
I'm expecting 8 CallingStations to be rendered (one for each in the array, which has a .length of 8). Here's CallingStation code:
class CallingStation extends Component {
render() {
console.log(`Rendered!`)
return (
<div>
<div>
Calling Station stop: { this.props.stopInfo ? this.props.stopInfo.location.crs : "" }
</div>
</div>
)
}
}
export default CallingStation;
On the page, there are 9 CallingStations (the first one doesn't have a 'this.props.stopInfo' but DOES have 'this.props.serviceId'.
Can anyone help me understand or point me in the direction of resources that are related?
The problem is here. There is an extra CallingStation in your render method :)
<h4>Current Journey ServiceID: {this.state.serviceId}</h4>
<CallingStation serviceId={this.state.serviceId}/>
In the JSON data the journeyData.service.stops.length will be 17. You can log it to the console using console.log(journeyData.service.stops.length) in your render method and remove this line <CallingStation serviceId={this.state.serviceId}/> it doesn't make sense before mapping. To work with large JSON data you better use a good json viewer i suggest this chrome extension it's fantastic JSON viewer Awesome.
render() {
console.log(journeyData.service.stops.length)
return (
<div>
<h1>CallingPattern page</h1>
<h4>Current Journey ServiceID: {this.state.serviceId}</h4>
<div className="calling-stations">
// journeyData is a local JSON file
{journeyData.service.stops.map((stop, i) => {
{console.log("mapping")} // logs 8 times (length of array)
return (
<CallingStation
key={`station-${i}`}
stopInfo={stop}
serviceId={this.state.serviceId}
/>
);
})}
</div>
</div>
);
}

Render Component Only Once in a Div Below an LI When In-Line Button is Clicked

Currently, this will render a component below each of the list items when the img is clicked by keeping an array of shown components per index in local state. Eg. (state.showItems ==[true,false,false,true]).
I would like to restrict the values in this array to only one 'true' at a time so that the <SuggestStep /> component is rendered only once in the div under the button that was clicked. I'm not using CSS because the list can grow very large and don't want to render and hide a component for each one. Also considered using a radio button displayed as an image, but don't know if that would involve mixing forms with LI's and if that is bad. Feedback on the question of restricting the showItems array items to only one true at a time, and general patterns to approaching the component rendering problem I'm describing are welcome.
class CurrentSteps extends Component {
constructor(props) {
super(props)
this.state = {
toggleOnSuggestInput: false,
showItems: []
}
this.clickHandler = this.clickHandler.bind(this)
}
clickHandler(index){
let showItems = this.state.showItems.slice();
showItems[index] = !showItems[index]
this.setState({showItems})
this.setState(prevState => ({
toggleOnSuggestInput: !prevState.toggleOnSuggestInput
}))
}
render() {
let steps = this.props.currentGoalSteps.map((step, index) => {
return (
<div key={`divKey${index}`}>
<li key={index}>{step}</li>
<img key={`imageKey${index}`} onClick={this.clickHandler.bind(this,index)} alt="" src={plus}/>
{this.state.showItems[index] ? <SuggestStep /> : null}
</div>
)
});
return (
<div>
<ul> {steps} </ul>
</div>
)
}
Try making the following modifications to your code...
Change your this.state like so.
this.state = {
toggleOnSuggestInput: false,
activeIndex: null
};
Change your clickHandler to this.
clickHandler(event, index) {
this.setState({ activeIndex: index })
}
Change your map to like the one below. Notice the onClick prop change.
let steps = this.props.currentGoalSteps.map((step, index) => {
return (
<div key={`divKey${index}`}>
<li key={index}>
{step}
</li>
<img
key={`imageKey${index}`}
onClick={e => this.clickHandler(e, index)}
alt=""
src={plus}
/>
{this.state.activeIndex === index ? <SuggestStep /> : null}
</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