I'm trying to hide a div using the following method in a react web page. But it doesn't hide the element. I can't see any errors in the developer tools as well.
if(pw.length==0){
document.getElementById('pwMeter').style.display='none'
}
What is the problem here? Does React support this method?
yes with react you can do this , check this sample ref code for that
import { useState } from "react";
const TestFunction = (props) => {
const [pw, setpw] = useState(["test"]);
return (
<div>
<div
id="pwMeter"
style={pw && pw.length > 0 ? { display: "bock" } : { display: "none" }}
>
<p>test data</p>
</div>
</div>
);
};
export default TestFunction;
Related
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/> }
let me explain my question.
I would like to create expanding flex cards, here is the exemple on codepen : https://codepen.io/z-/pen/OBPJKK
and here is my code for each button :
basically I have a component which is called HomeButtons that generates every flex cards. Inside this component I have a smaller component called readMore. In this component I have a useState that allows me to toggle individually each button to add or retreive an active class. If the active class is present, that means that the selected button must expand and the other ones must shrink.
What I would like to do is to access the readMore state ouside of the readMore subcomponent. That way I could write a function to remove the active class from a card if the user clicks on another card like so :
function setToUnactive() {
if (readMore(true)) {
readMore(false)}
}
My question is how can I get the state of readMore outside of the readMore subcomponent ? Do I need to use useContext ? Because that seems very simple to do but I tried a lot of things and nothing works. Can I pass the state readMore as a prop of the component ReadMore ? Thank you !
import React, { useState } from 'react';
import '../style/catalogue.scss';
import collectionsItems from '../Components/collectionsItemsData';
import { Link } from "react-router-dom";
const HomeButtons = ({}) => {
function ReadMore() {
const [readMore, setReadMore] = useState(false)
function toggleSetReadMore() {
setReadMore(!readMore)
}
return (
<p className='showmore' onClick={toggleSetReadMore} className={readMore ? "collection-item active" : "collection-item"}>TOGGLE BUTTON</p>
)
}
return <div>
{collectionsItems.map((collectionItem) => {
const { id, category, img } = collectionItem;
return < article key={id} >
<img className="item-img" src={img} alt=''/>
<ReadMore />
<Link to={`/${category}`} className="item-title">{category}</Link>
</article>
})}
</div>
}
export default HomeButtons;
First of all you need extract ReadMore component from function outside!
And for your problem you can lift state up(https://reactjs.org/docs/lifting-state-up.html). And since at the same time only one item can be opened you can do something like this:
function ReadMore({ isOpened, setOpened }) {
return (
<p
onClick={setOpened}
className={isOpened ? "collection-item active" : "collection-item"}
>
TOGGLE BUTTON
</p>
);
}
const HomeButtons = () => {
const [openedItemId, setOpenedItemId] = useState(null);
return (
<div>
{collectionsItems.map((collectionItem) => {
const { id, category, img } = collectionItem;
return (
<article key={id}>
<img className="item-img" src={img} alt="" />
<ReadMore
isOpened={openedItemId === id}
setOpened={() => setOpenedItemId(id)}
/>
<Link to={`/${category}`} className="item-title">
{category}
</Link>
</article>
);
})}
</div>
);
};
I have the following component to display a set of comments (and their replies). If a comment has a non-empty childPosts array, then the component is again called with the ids of the childPosts. All comments are accessible from redux store through props.discussionPosts.
import * as React from 'react';
import { useState } from 'react';
import { connect } from 'react-redux';
const CommentItem = (props) => {
return (
<div>
{
props.commentIds && props.discussionPosts &&
props.commentIds.map(commentId => {
console.log(props.discussionPosts[commentId].childPosts)
var ident = 10;
return (
<div key={commentId} className="comment">
<div>{props.discussionPosts[commentId].content}</div>
{
props.discussionPosts[commentId].childPosts.length > 0 &&
<div style={{ marginLeft: '10px'}}>
<CommentItem
key={commentId}
commentIds={props.discussionPosts[commentId].childPosts}
/>
</div>
}
</div>
)
})
}
</div>
)
}
const mapStateToProps = (state) => ({
discussionPosts: state.alignPerspectivesReducer.discussionPosts,
error: state.alignPerspectivesReducer.error,
loading: state.alignPerspectivesReducer.loading
})
export default connect(mapStateToProps)(CommentItem);
I place this component in the main page with the following code, where the commentIds is set to the ids of the comments with no parent comment.
<CommentItem
commentIds={props.discussionPosts.filter(function (x) {
return props.discussionPosts[x].parentPostId === null;
})}
/>
However, the code only displays the top level comments with no parent comment:
Comment 1
Comment 2
What I want to achieve is this:
Comment 1
Reply to c#1
Comment 2
Reply to c#2
But, for some reason the following code inside the CommentItem component is not producing them:
<CommentItem
key={commentId}
commentIds={props.discussionPosts[commentId].childPosts}
/>
I am able to print the childPosts values correctly in the console. Below in the image you can see how the discussionPosts data looks like:
I am not receiving any error, but this recursive component does not work properly. Any help?
I don't have enough knowledge about redux but what if you create a component with connect and render it?
const CommentItem = (props) => {
return (
<div>
{
props.commentIds && props.discussionPosts &&
props.commentIds.map(commentId => {
console.log(props.discussionPosts[commentId].childPosts)
var ident = 10;
return (
<div key={commentId} className="comment">
<div>{props.discussionPosts[commentId].content}</div>
{
props.discussionPosts[commentId].childPosts.length > 0 &&
<div style={{ marginLeft: '10px'}}>
{// render connected component}
<ConnectedCommentItem
key={commentId}
commentIds={props.discussionPosts[commentId].childPosts}
/>
</div>
}
</div>
)
})
}
</div>
)
}
const mapStateToProps = (state) => ({
discussionPosts: state.alignPerspectivesReducer.discussionPosts,
error: state.alignPerspectivesReducer.error,
loading: state.alignPerspectivesReducer.loading
})
// create connected component
const ConnectedCommentItem = connect(mapStateToProps)(CommentItem);
export default ConnectedCommentItem;
It looks like your childPosts might be an object rather than an array. If the data is structured like this:
childPosts: {
0: 2
}
then childPosts.length will be undefined and your recursive element will never be rendered.
What you want is an array:
childPosts: [ 2 ]
then your code should work as written.
Use hasChildPosts instead of props.discussionPosts[commentId].childPosts.length > 0
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.
I am making a small application in React that fetches a random image using Axios. I am using React-bootstrap to style the image, however a small white box is displayed for half of a second before the image is done loading. How can I resolve this?
This is my code:
import React, { Component } from 'react';
import axios from 'axios';
import { Link } from 'react-router-dom';
import { Image, Button } from 'react-bootstrap';
const ROOT_URL = 'myurl'
export default class WhatDog extends Component {
constructor(props){
super(props);
this.state = { randomImg: '' };
}
componentDidMount(){
axios.get(ROOT_URL)
.then(res => {
const data = res.data.message
this.setState({ randomImg: data })
})
}
renderImage(){
return(
<div>
<Image src={this.state.randomImg} className="img" thumbnail/>
<Link to="/">
<Button bsStyle="danger" bsSize="large">Go back</Button>
</Link>
</div>
)
}
render() {
return (
<div className="App">
{
(this.state.randomImg === '')
? <div>
<h1>Loading...</h1>
</div>
: <div>
{this.renderImage()}
</div>
}
</div>
);
}
}
The browser will fire the onLoad event, after the image has been, you name it.. loaded so before that, set the visibility to hidden.. NOT display: none ! Because display: none will also prevent the loading.
The solution might look something like this
<Image
src={this.state.randomImg}
style={!this.state.imgVisible ? {visibility: 'hidden'} : {}}
onLoad={() => this.setState({ imgVisible: true })}
/>
Note: This is using inline styles and arrow functions, which is not best, but for simplicity of the demo its enough, you could also you a className instead, its up to you ;)
You got the idea...