Conditional render of props in react - javascript

I have this 2 states, from 2 different api calls
one is 'movieList' and the other one is 'search', Both are array of movies.
movieList is automatically rendered since it is the search for popular movies and it corresponds that the user is shown as soon as he opens the page, in the navbar I have an input attached to a state called search and it saves an array of movies that match the name in it ... try to use a conditional with the following logic, if search exists, maps search, otherwise map movieList.
but it seems I don't know how to do it correctly. If someone can give me a hand in how to do it, it would help me a lot, thank you very much! here I leave the code
import { useSelector } from 'react-redux'
import { getAllMovies } from '../../features/movieSlice'
import MovieCard from '../MovieCard/MovieCard';
const MovieListing = ({ movieList, search }) => {
return (
<div className='' >
<div className=''>
<div className='my-20 mx-15 flex flex-wrap justify-around items-center' >
{
movieList.map((movie)=>(
<MovieCard {...movie} key={movie.id} />
))}
</div>
</div>
</div>
)
}
export default MovieListing```

To do a conditional render you can try use a ternary operator:
<div className='' >
<div className=''>
<div className='my-20 mx-15 flex flex-wrap justify-around items-center' >
{
search ? search.map((searchItem) => <MapsSearch {...search}/> :
movieList.map((movie) => (<MovieCard {...movie} key={movie.id}/>))
}
</div>
</div>
</div>
(You'll just need to modify the mapping of search and what it returns as I'm not sure what type search is)

Related

How to refetch properly an API request after an event occurred?

i'm a react beginner and I'm struggling with the refresh of the components.
In this case, I have a GET request to an API triggering in a useEffect hook with no dependencies on my App.js. Of course, this is working just fine when my app just starts. However, I need it to trigger again after certain events ocurre, like an Onclick event in a button, and a OnSubmit event in a form, in order to re render the updated table component where the API data is displayed.
What is the best way to do this?
I thought about just calling the fetch function again whenever I need to update the data, but I don't know if that's the way to go.
Then, I currently have this workaround function to force the reload of the entire page after the events trigger, but i'm pretty sure this is not proper either:
const refresh = () =>{
window.location.reload(false);
}
I've been also tweaked the dependencies in the use effect (where the fetch happens) a little bit, because I'm feeling like the solution is there, but I had only bad results, like infinite loops.
Finally guys, I'll post an overview pic of my App code. Have in mind that I need to do the refresh in the next components: OrdenPago y Grid.
import { useState, useEffect } from 'react';
import { OrdenPago } from './OrdenDePago';
import EstadoCvus from './EstadoCvus';
import Grid from './Grid';
import axios from 'axios';
export const App = () => {
const [ops, setOps] = useState({ ordenesPago: [] });
useEffect( () => {
axios.get("http://cpawautojava:1400/consultaOrdenesPago")
.then(response => {
setOps(response.data);
console.log(response.data);
}).catch((error) => { console.log(error) })
}, [])
return (
<div className="container">
<div className='row'>
<div className='col-12'>
<div className='text-white py-2' style={{ backgroundColor: "#414BB2", height: "40px" }} >
<h1 className='text-center lead fw-bold'>GestiĆ³n de OPs</h1>
</div>
</div>
</div>
<div className='row mt-3' >
<div className='col-6 d-flex justify-content-center'>
<OrdenPago />
</div>
<div className='col-6 form1' >
<EstadoCvus />
</div>
</div>
<div className='row'>
<div className='col-12' >
<Grid ops={ops} />
</div>
</div>
</div>
);
}
Thanks in advance for your help.
Rodrigo.

how to hide a button depending on the selected file

I'm making a blog where I need a button to appear only if a user selects a specific story, if the user selects other reports, the button should not appear.
These reports are in markdown file.
I thought of using a conditional rendering with a state and use
{
Show && (<div><div/>)
}
Here's the code where the commented part what was trying to do something
import markdownStyles from './markdown-styles.module.css'
import Show_button_1 from './show_button_1'
export default function PostBody({ content }) {
/*const retornarPagina=()=>{
if(content==_posts.receita_0.md){
return
<Show_button_1/>
}
*/
return (
<div className="max-w-2xl mx-auto">
<div
className={markdownStyles['markdown']}
dangerouslySetInnerHTML={{ __html: content }}
/>
<Show_button_1/>
</div>
)
}
I tried to do it this way but it didn't work (03/30/2022)
import React, {useState} from 'react'
import markdownStyles from './markdown-styles.module.css'
import Show_button_1 from './show_button_1'
export default function PostBody({ content }) {
const [Show, setShow] = useState(false);
const retornarPagina=()=>{
if(content===_posts.receita_0.md){
{setShow(true)}
}
}
return (
<div className="max-w-2xl mx-auto">
<div
className={markdownStyles['markdown']}
dangerouslySetInnerHTML={{ __html: content }}
/>
{Show && (<Show_button_1/>)}
</div>
)
}
I'm not sure I understood the question correctly, but one crutch I used to conditionally render components was
{
Show ? (<div><div/>) : (<></>) //doesn't render anything
}
This should work for you.
{content === '_posts.receita_0.md' && <Show_button_1/> }
If you need multiple lines:
{content === '_posts.receita_0.md' && (
<Show_button_1/>
)}
you won't be able to use conditional rendering on a full file, you may want to consider refactoring your code to send a title of the markdown file through props as well. so you would do something like so:
<MyComponent content={document.markdown} title={document.title}/>
Then you can easily do
{props.title === 'some_title' && <Show_button_1/> }

How to fix unique "key" prop and validateDOMNesting(...) in ReactJS with fuctional component

Hi all I have following code.
Test.js component
const Test = ({ infoText }) => {
return (
<div>
Some Text
{infoText && <p>{infoText}</p>}
</div>
);
};
export default Test;
App.js component
export default function App() {
return (
<div className="App">
<Test
infoText={[
<p className="someStyles">"Looking to lease multiple devices?"</p>,
<div className="someOtherStyles">
<b>Get in contact with our specialist.</b>
</div>,
]}
/>
</div>
);
}
When I am rendering my Test component in App.js file I am getting errors like
Warning: Each child in a list should have a unique "key" prop.
Warning: validateDOMNesting(...): <div> cannot appear as a descendant of <p>.
I know that is coming from this syntax that I wrote.
infoText={[
<p className="someStyles">"Looking to lease multiple devices?"</>,
<div className="someOtherStyles">
<b>Get in contact with our specialist.</b>
</div>,
]}
I need to write in this way because my Test component is reusable component and I am using it's infoText prop for passing various tags with specific classes.
By the way, the code works. But it's very ugly that I have so many errors in the console. Please help me fix this.
This warning is generated because usually, when a react element is an array, that array is generated dynamically, and so might change. In this scenario, you absolutely need the elements in your list to have a unique key prop to avoid unexpected behaviour from React.
In this scenario, you are absolutely fine to ignore the warnings, because your array is hardcoded, and is never going to change. If you don't want to see these warnings, you could change the array to be a react fragment, like this:
const Test = ({ infoText }) => {
return (
<div>
Some Text
{infoText && <p>{infoText}</p>}
</div>
);
};
<Test
infoText={
<>
<p className="someStyles">"Looking to lease multiple devices?"</p>
<div className="someOtherStyles">
<b>Get in contact with our specialist.</b>
</div>
</>
}
/>
A more idiomatic way of achieving the same thing might be to have your Test component render its children, like this:
const Test = ({ children }) => {
return (
<div>
Some Text
<p>{children}</p>
</div>
);
};
<Test>
<p className="someStyles">"Looking to lease multiple devices?"</p>
<div className="someOtherStyles">
<b>Get in contact with our specialist.</b>
</div>
</Test>

Why I get props is undefined?

import React from "react";
import styles from "../articles.css";
const TeamInfo = props => (
<div className={styles.articleTeamHeader}>
<div className={styles.left}>
style={{
background: `url('/images/teams/${props.team.logo}')`
}}
</div>
<div className={styles.right}>
<div>
<span>
{props.team.city} {props.team.name}
</span>
</div>
<div>
<strong>
W{props.team.stats[0].wins}-L{props.team.stats[0].defeats}
</strong>
</div>
</div>
</div>
);
export default TeamInfo;
the code that render this
import React from 'react';
import TeamInfo from '../../Elements/TeamInfo';
const header = (props) => {
const teaminfofunc = (team) => {
return team ? (
<TeamInfo team={team}/>
) : null
}
return (
<div>
{teaminfofunc(props.teamdata)}
</div>
)
}
export default header;
and I am getting error TypeError: props is undefined in line 8 why is that ?
Line 8 is
background: url('/images/teams/${props.team.logo}')
Update:
I found that in index.js the componentWillMount bring the data correctly but in the render() those data (article and team) was not passed to render, any idea why ?
import React, {Component} from 'react';
import axios from 'axios';
import {URL} from "../../../../config";
import styles from '../../articles.css';
import Header from './header';
import Body from './body';
class NewsArticles extends Component {
state = {
article:[],
team: []
}
componentWillMount() {
axios.get(`${URL}/articles?id=${this.props.match.params.id}`)
.then(response => {
let article = response.data[0];
axios.get(`${URL}/teams?id=${article.team}`)
.then(response => {
this.props.setState({
article,
team:response.data
})
})
})
}
render() {
const article = this.state.article;
const team = this.state.team;
return (
<div className={styles.articleWrapper}>
<Header teamdata={team[0]} date={article.date} author={article.author} />
<Body />
</div>
)
}
}
export default NewsArticles;
You render your component immediately, long before your AJAX call finishes, and pass it the first element of an empty array:
<Header teamdata={team[0]}
componentWillMount does not block rendering. In your render function, short circuit if there's no team to render.
render() {
const { article, team, } = this.state;
if(!team || !team.length) {
// You can return a loading indicator, or null here to show nothing
return (<div>loading</div>);
}
return (
<div className={styles.articleWrapper}>
<Header teamdata={team[0]} date={article.date} author={article.author} />
<Body />
</div>
)
}
You're also calling this.props.setState, which is probably erroring, and you should never call setState on a different component in React. You probably want this.setState
You should always gate any object traversal in case the component renders without the data.
{props && props.team && props.team.logo ? <div className={styles.left}>
style={{
background: `url('/images/teams/${props.team.logo}')`
}}
</div> : null}
This may not be you exact issue, but without knowing how the prop is rendered that is all we can do from this side of the code.
Update based on your edit. You can't be sure that props.teamdata exists, and therefore your component will be rendered without this data. You'll need to gate this side also, and you don't need to seperate it as a function, also. Here is an example of what it could look like:
import React from 'react';
import TeamInfo from '../../Elements/TeamInfo';
const header = (props) => (
<div>
{props.teamdata ? <TeamInfo team={props.teamdata}/> : null}
</div>
)
export default header;
First -- while this is stylistic -- it's not good practice to pass props directly to your functional component. Do this instead.
const TeamInfo = ({team}) => (
<div className={styles.articleTeamHeader}>
<div className={styles.left}>
style={{
background: `url('/images/teams/${team.logo}')`
}}
</div>
<div className={styles.right}>
<div>
<span>
{team.city} {team.name}
</span>
</div>
<div>
<strong>
W{team.stats[0].wins}-L{team.stats[0].defeats}
</strong>
</div>
</div>
</div>
);
Second, you might just want to do some kind of null check. If team is undefined the first time the component tries to render, you might just want to render null so you're not wasting cycles.
In case this isn't the issue, you'd learn a lot by console.log-ing your props so you know what everything is each time your component tries to render. It's okay if data is undefined if you're in a state that will soon resolve.

Update functionality in react

I am newbie to React and I am trying to do update on react. I don't get the exact logic to make it and hence I need your help.
On click of update, I managed to get the values of selected contact but later on, i don't get how to populate those value onto input text boxes and again on submit after change of values, update the selected contact. I came across onChange but I don't understand.
Clues i knew:
this.refs.name.value and this.refs.number.value are values which are in input textbox . And on update, we need to set these value into the state on that corresponding index.
My code and screenshot is below:
Person.js - number is taken as the key , considering individual number is unique
editcontact(id){
this.props.onChange(id);
}
render() {
return(
<div className="panel panel-default">
<div className="panel-heading">
<h4>{this.props.detail.name} </h4>
<a className="b" href="#" onClick={this.deletecontact.bind(this,this.props.detail.number)}> Delete </a>
<a className="b" href="#" onClick={this.editcontact.bind(this,this.props.detail.number)}> Update </a>
</div>
<h6 className="panel-body">{this.props.detail.number}</h6>
</div>
</div>
)
}
It is passed to Contact.js
editcontact(id)
{
this.props.onChange(id);
}
render() {
var details;
if(this.props.data){
details=this.props.data.map(dts=>{
return(
<Person key={dts.number} detail={dts} onChange={this.editcontact.bind(this)} onDelete={this.deletecontact.bind(this)}></Person>
)
})
}
Then comes App.js
handleEdit(id){
console.log(id);
let cts=this.state.contacts;
let index=cts.findIndex( x => x.number === id);
console.log(cts[index]);
this.setState({ selectedContact: cts[index]; });
}
render() {
return (
<div className="App">
<div className="page-header">
<h2>Contact list</h2>
</div>
<AddContact newOne={this.state.selectedContact} addcontact={this.handleAddition.bind(this)}></AddContact>
<Contact onChange={this.handleEdit.bind(this)} onDelete={this.handleDelete.bind(this)} data={this.state.contacts}> </Contact>
</div>
);
}
AddContact.js
constructor(){
super();
this.state={
newContact:{
name:'',
number:''
}
}
}
addcontact(e){
// console.log(this.refs.name.value);\
e.preventDefault();
this.setState({
newContact:{
name: this.refs.name.value,
number:this.refs.number.value
}
},function(){
console.log(this.state.newContact);
this.props.addcontact(this.state.newContact);
})
this.refs.name.value="";
this.refs.number.value="";
}
render() {
console.log(this.props.newOne);
return (
<div className="col-md-6">
<form onSubmit={this.addcontact.bind(this)}>
<div className="form-group">
<label>Name </label>
<input className="form-control" type="text" ref="name" />
</div>
<div className="form-group">
<label>Number</label>
<input className="form-control" type="number" ref="number" />
</div>
<input type="submit" value="Submit"/>
</form>
</div>
);
}
}
what you need is to tell your component that you have a new state and you want it to re-render.
handleEdit(id){
console.log(id);
let cts=this.state.contacts;
let index=cts.findIndex( x => x.number === id);
this.setState({ selectedContact: cts[index]; });
}
render() {
return (
<div className="App">
<div className="page-header">
<h2>Contact list</h2>
</div>
<AddContact addcontact={this.handleAddition.bind(this)}></AddContact>
<Contact onChange={this.handleEdit.bind(this)} onDelete={this.handleDelete.bind(this)} data={this.state.contacts}> </Contact>
</div>
);
with the setState function you updating the state of this compoent and also make it to re-render. now you can decide what you want to do with this data: this.state.selectedContact like passing it to AddContact
Don't use .bind(this... there is no reason to do it. Use attribute={() => this.functionName()}
Don't use different naming, use some pattern for attributes names. e.g. addcontact should be addContact
Don't use so long lines. Use Eslint to show you all of such tips.
It's really hard to read your code now, make it more readable and you will have better time editing it yourself.
And now to have update, i would suggest using pure functional component to display things and higher order component to manage state of data.
(props) => <form> .... <input value={props.email} /> ... </form;
and in parent component, which is responsible for all data management add state. In state you can save values and pass it into child components using props.
When you will advance in React, you will start using extra libraries to manage state of the app, e.g. Redux. It makes similar thing, but all app's state is in one place and then you can access it from any part of the app. E.g. you show these inputs, then jump to another state of app to add some other thing and then you can easily jump back to this state and still have input's values that are partly entered.
Just save values in state. No matter how you manage your app's state and push values to display components using props. Google, read, check some videos on Youtube and you will get it.
https://facebook.github.io/react/docs/thinking-in-react.html

Categories

Resources