In the react component, there is a form used to post a comment. When I post a comment, it gets submitted and appears in the database. Using map function, I'm trying to display the blog comments on the browser but it just does not appear on the browser. I can see the array of comments in the redux devtools.
<Container className="content">
<div>
<h1 className='display-2'>{blog.title}</h1>
<Image src={blog.image} />
<h2 className='text-muted mt-3'>Category: {blog.category}</h2>
<div className='mt-5 mb-5' dangerouslySetInnerHTML={createBlog()} />
</div>
<div>
{blog?.post?.comments.length === 0 && <Message variant='info'>No comment yet</Message>}
<div>
{blog?.post?.comments.map((comment) => (
<div key={comment?.id}>
<strong>{comment?.name}</strong>
<p>{comment?.dateCreated.substring(0, 10)}</p>
<p>{comment?.comment}</p>
</div>
))}
</div>
{blogCommentLoading && <Loader />}
{blogCommentSuccess && <Message variant='success'>Comment Submitted</Message>}
{blogCommentError && <Message variant='danger'>{blogCommentError}</Message>}
<Form onSubmit={submitHandler}>
<Form.Group controlId='comment'>
<Form.Label>Comment</Form.Label> {/* The label called review is named comment in the database(backend)*/}
<Form.Control
as='textarea'
row='5'
value={comment}
onChange={(e) => setComment(e.target.value)}
></Form.Control>
</Form.Group>
<Button type='submit' variant='primary'>Submit</Button>
</Form>
</div>
</Container>
);
};
What am I missing out, how do I make the comments to appear on the browser?
Replace
{blog?.post?.comments.length === 0 && <Message variant='info'>No comment yet</Message>}
<div>
{blog.post.comments.map((comment) => (
<div key={comment?.id}>
<strong>{comment?.name}</strong>
<p>{comment?.dateCreated.substring(0, 10)}</p>
<p>{comment?.comment}</p>
</div>
))}
</div>
with:
{!blog?.post?.comments?.length ? (
<Message variant='info'>No comment yet</Message>
) : (
<div>
{blog?.post?.comments.map((comment) => (
<div key={comment?.id}>
<strong>{comment?.name}</strong>
<p>{comment?.dateCreated.substring(0, 10)}</p>
<p>{comment?.comment}</p>
</div>
))}
</div>
)}
Related
Whenever I try to search, I can type only the letters which are similar to the one of the titles. If any letter is different I lose focus from input. It used to work normally before, but Idk what happened now. Any suggestions?
How it first looks like:
After starting to type on search input:
When I type a letter which is not in the title:
Code:
if (props.items.length === 0) {
return (
<div className="files-list center">
<Card>
<h2>No files found.</h2>
</Card>
</div>
);
} else if (
props.items.filter(
(file) =>
file.title.toLowerCase().includes(searchInput) ||
file.title.toUpperCase().includes(searchInput)
).length === 0
) {
return (
<div className="filesList">
<div className="search">
<input
type="text"
placeholder="Search Files"
onChange={(event) => setSearchInput(event.target.value)}
/>
</div>
<Card>
<h2>No files found.</h2>
</Card>
</div>
);
}
return (
<React.Fragment>
<div className="filesList">
<div className="actionsBtn">
<NavLink to="/add-file" className="addFileBtn" title="Add File">
<FontAwesomeIcon icon={faPlus} />
</NavLink>
<input
type="text"
placeholder="Search Files"
onChange={(event) => setSearchInput(event.target.value)}
/>
</div>
<ul className="files-list">
{props.items
.filter(
(file) =>
file.title.toLowerCase().includes(searchInput) ||
file.title.toUpperCase().includes(searchInput)
)
.map((file) => (
<FilesPostItem
key={file.id}
id={file.id}
title={file.title}
file={file.file}
creator={file.creator.name}
description={file.description}
creatorId={file.creator}
onDelete={props.onDeleteFile}
/>
))}
</ul>
</div>
</React.Fragment>
);
What I think happens is, your “default” return form the beginning gets reset by the return in the “if else”. So the Input is a new DOM Element and loses focus.
You might want to add something like this to your default return and remove your "if else" statement.
<ul className="files-list">
{props.items
.filter(
(file) =>
file.title.toLowerCase().includes(searchInput) ||
file.title.toUpperCase().includes(searchInput)
)
.map((file) => (
<FilesPostItem
key={file.id}
id={file.id}
title={file.title}
file={file.file}
creator={file.creator.name}
description={file.description}
creatorId={file.creator}
onDelete={props.onDeleteFile}
/>
))}
</ul>
{props.items
.filter(
(file) =>
file.title.toLowerCase().includes(searchInput) ||
file.title.toUpperCase().includes(searchInput)
).length > 0 &&
<Card>
<h2>No files found.</h2>
</Card>
}
What does this do?
It adds the "No files found" message to your default return and shows it only, if items is empty.
But i am pretty sure, there is a better way to do this.
I would like to add a popup form in each item in the Flatlist, and the item is actually a card.
My problem is that every time, I clicked the button, the popup shows but, when my mouse moves out of the card, instead of showing the original one, it shows another popup whose parent is the whole page.
I know the problem should be that I need not set the variable setPopup properly. But I don't know how to fix it.
When my mouse is on the card:
enter image description here
When my mouse is out of the card, the popup will move up and its position will be based on the whole page:
enter image description here
Thank you!
This is my code.
const [buttonPopUp, setButtonPopUp] = useState(undefined);
const renderItem = (item, index) => {
return(
<Card key={index} style={{width: '20rem'}}>
<CardImg className='galleryPics' top src={galleryPic.img} alt="..."/>
<CardBody>
<PopUpEditGallery
gallery={item}
index = {index}
trigger={buttonPopUp}
setTrigger={setButtonPopUp}
>
Edit
</PopUpEditGallery>
<CardTitle className='cardTitle'>{item.title}</CardTitle>
<CardText className='cardText'>{item.description}</CardText>
<Button className="btn-round btn-icon" color="primary" size='sm' onClick={()=> setButtonPopUp(index)}>Edit</Button>
</CardBody>
</Card>
);
}
return (
<div>
<div>
<Header/>
</div>
<div className="container">
<div className="row">
<div className='col-7'>
<ul>
<FlatList
list={values.gallery}
renderItem={renderItem}/>
</ul>
</div>
</div>
</div>
</div>
)
code for popup
return (props.trigger != undefined) ? (
props.trigger == props.index &&
<div className='popup'>
<div className='popupInner'>
<form onSubmit={handleSubmit(onSubmit)}>
<FormGroup>
<Label>Title</Label>
<Input
type="text"
placeholder={prev.title}
onChange={val => props.setTitle(val.target.value, prev.idx)}
/>
</FormGroup>
<Button className="btn-round btn-icon" color="primary" size='sm'>
Submit
</Button>
<Button className="btn-round btn-icon" color="default" size='sm'>
Cancel
</Button>
</form>
</div>
</div>
): "";
I want to build a searching page with Reactive search, and when users scroll the search results to the bottom, they can find a "Load More" button, by clicking it, the next page will be loaded. I found that in the document, there is a callback function called "handleLoadMore()", but I don't know how to use it.
The code I wrote is just like this.
<ReactiveList
className={classes.content}
dataField={"description"}
componentId={"SearchResult"}
react={{ and: ["DataSearch"] }}
pagination={false}
scrollOnChange={true}
stream={true}
showResultStats={true}
renderResultStats={stats => {
return (
<div>
<p className={classes.stats}>
{stats.numberOfResults} results available based on your location
</p>
<img
className={classes.logo_color}
src={require("../../images/logo-color.png")}
alt="logo-color"
/>
</div>
);
}}
paginationAt="bottom"
size={12}
infiniteScroll={true}
loader="Loading Results.."
>
{({ data, handleLoadMore }) => {
return (
<ResultCardsWrapper className={classes.cardsWrapper}>
{data.map((element, index) => {
console.log(data);
return (
<ResultCard className={classes.card} key={index} target={"_self"}>
<Link
className={classes.wrapper}
to={`/shop/${element._index}/${element._id}`}
>
<ResultCard.Image
className={classes.image}
src={getLogo(element.logo)}
/>
<ResultCard.Title className={classes.title}>
{element.title}
<div className={classes.shopIcons}>
{console.log(element.opening_hour[curDay].open)}
{curTime <= element.opening_hour[curDay].close &&
curTime >= element.opening_hour[curDay].open ? (
<img
src={require("../../images/Icon ionic-md-time.svg")}
alt="open"
/>
) : (
<img
src={require("../../images/Icon ionic-md-time-closed.svg")}
alt="open"
/>
)}
<img
src={require("../../images/Icon material-local-offer.svg")}
alt="offer"
/>
</div>
</ResultCard.Title>
</Link>
</ResultCard>
);
})}
<button onClick={handleLoadMore}>Load More</button>
</ResultCardsWrapper>
);
}}
</ReactiveList>;
you can replace the handleLoadMore to loadMore, it works for me.
I would like to delete a search result by clicking on the X icon on the individual card.
The search returns 10 recipes from the API, generating 10 divs. How would I go about removing individual divs onClick of the icon whilst keeping the other divs? Essentially just a remove search result button.
return (
<div className='App'>
<form onSubmit={getSearch} className="search-form">
<InputGroup>
<InputGroupAddon addonType="prepend">
<InputGroupText><FontAwesomeIcon icon={faSearch} /></InputGroupText>
</InputGroupAddon>
<Input className="search-bar" type="text" placeholder="Search for recipe..." value={search} onChange={updateSearch} />
</InputGroup>
<Button color="primary" size="sm" className="search-button" type="submit">Search</Button>
</form>
<div className="recipes">
{recipes.map(recipe => (
<Recipe
key={recipe.recipe.label}
title={recipe.recipe.label}
theUrl={recipe.recipe.url}
image={recipe.recipe.image}
ingredients={recipe.recipe.ingredients}
source={recipe.recipe.source}
healthLabels={recipe.recipe.healthLabels}
servings={recipe.recipe.yield} />
))}
</div>
</div>
const Recipe = ({ title, theUrl, image, ingredients, source, healthLabels, servings }) => {
return (
<div className={style.recipe}>
<FontAwesomeIcon className={style.delete} icon={faTimes} />
<h3 >{title}</h3>
<Badge className={style.badge} color="primary">{source}</Badge>
<p>Serves: <Badge color="primary" pill>{servings}</Badge></p>
<img src={image} alt='food' />
<ol className={style.allergens}>
{healthLabels.map(healthLabel => (
<li>{healthLabel}</li>
))}
</ol>
<div className={style.ingr}>
<ol>
{ingredients.map(ingredient => (
<li>{ingredient.text}</li>
))}
</ol>
<Button className={style.button} outline color="primary" size="sm" href={theUrl} target="_blank">Method</Button>
</div>
<div className={style.info}>
<div className={style.share}>
<WhatsappShareButton url={theUrl}><WhatsappIcon round={true} size={20} /></WhatsappShareButton>
<FacebookShareButton url={theUrl}><FacebookIcon round={true} size={20} /></FacebookShareButton>
<EmailShareButton url={theUrl}><EmailIcon round={true} size={20} /></EmailShareButton>
</div>
</div>
</div>
);
}
Simply update the recipes array and React will update the HTML.
I'm not sure where recipes comes from, but if you set an onClick on, say, <Recipe label="x"> that deletes the corresponding recipe element from recipes, then React should no longer render that recipe.
That should be easy. Here's one way:
add onClick to this
<FontAwesomeIcon onClick={deleteRecipe} className={style.delete} icon={faTimes} />
pass a reference of the function that deletes the recipe.
deleteRecipeHandler = (id) => {
// filter your recipes here such that the new recipes array doesn't contain the recipe
// with the id you're getting here.
// Change the below code how you need
const newRecipes = oldRecipes.filter(recipe => {
return recipe.id !== id;
});
}
{recipes.map(recipe => (
<Recipe
key={recipe.recipe.label}
deleteRecipe={this.deleteRecipeHandler.bind(this,recipe.recipe.id)}
title={recipe.recipe.label}
theUrl={recipe.recipe.url}
image={recipe.recipe.image}
ingredients={recipe.recipe.ingredients}
source={recipe.recipe.source}
healthLabels={recipe.recipe.healthLabels}
servings={recipe.recipe.yield} />
))}
since you're destructuring your props you can use
const Recipe = ({ title, theUrl, image, ingredients, source, healthLabels, servings, deleteRecipe }) => {
return (
<div className={style.recipe}>
<FontAwesomeIcon onClick={deleteRecipe} className={style.delete} icon={faTimes} />
This question already has answers here:
Warning: Unreachable code , using Reactjs
(2 answers)
Closed 4 years ago.
My reactjs app has a warning unreachable code no-unreachable, has anyone ever experienced or helped my problem
the error if else return statement
the error is in the section :
)
}
return (
Thank you in advance
const listNews = [];
if (<Route path="/berita/:id" component={ViewsBerita} />) {
return(
<div>
<GridItem xs={12} sm={12} md={8}>
<div className={classes.section} style={styleTitle}>
<div className={classes.container}>
<HashRouter>
<Route path="/berita/:id" component={ViewsBerita} />
</HashRouter>
</div>
</div>
</GridItem>
</div>
);
} else {
return(
<div>
<GridItem xs={12} sm={12} md={7}>
<div style={style}>
<ul>
{renderTodos}
</ul>
<br />
<ul style={pagination}>
{renderPrevBtn}
{pageDecrementBtn}
{renderPageNumbers}
{pageIncrementBtn}
{renderNextBtn}
</ul>
</div>
</GridItem>
</div>
)
}
return (
<div>
<Headers />
<div className={classNames(classes.main, classes.mainRaised)} key="i">
<br />
<GridContainer>
<GridItem xs={12} sm={12} md={12}>
<div className={classes.section} style={styleTitle}>
<div className={classes.container}>
<h1> <b> Berita & Event </b> </h1>
<div style={{ width: '25%', marginLeft: '37%' }}>
<p style={{ border: '1px solid', borderColor: 'yellow'}} > </p>
</div>
</div>
</div>
</GridItem>
{listNews}
</GridContainer>
<Footers />
</div>
<Footer />
<ScrollToTop showUnder={160} style={{zIndex: 100 }}>
<span> <img src={Up} alt="up" style={{ width: '40px', height: '40px' }} /> </span>
</ScrollToTop>
</div>
);
}
}
export default withStyles(componentsStyle)(Components);
My reactjs app has a warning unreachable code no-unreachable, has anyone ever experienced or helped my problem
the error if else return statement
the error is in the section :
)
}
return (
Thank you in advance
That is because that last return statement will never work. You already have an if...else statement. Which means either of that will work and either of that will return (either the if condition or the else condition will work), and your code will never under any circumstances go to the last return statement and therefore that code is unreachable.