React-bootstrap cards not wrapping - reactjs

My Code is:
import React, { useEffect, useState } from "react";
import styles from "./Cards.module.css";
import { CardDeck, Card } from "react-bootstrap";
const Cards = ({ animeArray }) => {
const [aanimeArray, setAnimeArray] = useState([]);
useEffect(() => {
setAnimeArray(animeArray);
}, [animeArray]);
if (!aanimeArray) {
return;
}
console.log("Anime Array", aanimeArray);
return (
<div className={styles.container}>
{aanimeArray === [] ? (
<h1>Search</h1>
) : (
<CardDeck>
{aanimeArray.map((anime) => {
return (
<Card>
<Card.Img variant = "top" src={anime.image_url} />
<Card.Body>
<Card.Title>{anime.title}</Card.Title>
</Card.Body>
<Card.Footer>
<small className="text-muted">{anime.rated}</small>
</Card.Footer>
</Card>
);
})}
</CardDeck>
)}
</div>
);
};
export default Cards;
I am not using any custom styling whatsoever.
The result of the above mentioned code is as seen on this image:
Image of the issue

You have to make the effort of making them wrap. In fact, as seen on the documentation, majority of the developers' examples includes the CSS property width with a value of 18rem.
Here is an example by leveraging minWidth:
const sampleStyle = {
minWidth: "20%",
flexGrow: 0
};
<Card style={sampleStyle}>

First thing.
aanimeArray === []
won't work since you are comparing an array with another array.
Best way in Javascript for this is to check the length of the array.
aanimeArray.length === 0
means it is an empty array.
About the styling I think you need to show us the CSS code as well. I'm not sure what CardDeck component does...

Related

React: prevent list from rerendering all elements on prop change

I'm trying to recreate the effect shown at https://hexed.it/
When you hover over either list the corresponding byte in the other list is also highlighted. I figured a panel with each list inside it that had a state with the current hovered byte would do but it seems that React wants to re-render the entire list or do something strange every time resulting in larger files being unbearably slow.
I see a lot of "use memo! use the useCallback hook!" when searching and I've tried... it's still slow and I'm not sure why. It seems like it's only rendering the updated HexByte but it's still unacceptably slow for large files.
Sandbox: https://codesandbox.io/s/flamboyant-ellis-btfk5s
Can someone help me quicken/smooth out the hovering?
I solved it using this answer: Prevent DOM element re-render in virtualized tree component using react-window
In short the things I've learned:
memo has no effect if a component has a useState in it
Large lists of data should be rendered using a library like react-window
The cell rendering function as mentioned in the answer above can't be part of a parent component
As an example for anyone coming here, the new HexPanel class looks like so
import Box from '#mui/material/Box';
import { memo } from 'react';
import { FixedSizeGrid as Grid, areEqual } from 'react-window';
const HexByte = memo(function HexByte(props) {
const onMouseEnter = () => {
props.onHover(props.index);
//setInside(true);
}
const onMouseLeave = () => {
//setInside(false);
}
const onClick = () => {
//setClicked(true);
}
return (
<span
style={{
display: 'inline-block',
padding: '5px',
backgroundColor: props.hoverIndex == props.index ? '#777' : 'transparent',
color: 'darkblue'
}}
onClick={onClick}
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
>
{props.byte}
</span>
)
}, (prevProps, nextProps) => nextProps.hoverIndex != nextProps.index);
const Cell = memo(function({ data, columnIndex, rowIndex, style }) {
return (
<div style={style}>
<HexByte byte={data.hex[rowIndex][columnIndex]} onHover={data.onHover} hoverIndex={data.hoverIndex} index={`${rowIndex}${columnIndex}`} />
</div>
)
}, areEqual);
const HexPanel = (props) => {
return (
<Box
sx={{
fontFamily: 'Source Code Pro',
display: 'flex',
flexDirection: 'column',
}}
>
<Grid
columnCount={16}
columnWidth={30}
height={900}
itemData={props}
rowCount={props.hex.length}
rowHeight={35}
width={500}
>
{Cell}
</Grid>
</Box>
)
}
export default HexPanel;

Material UI Rating wrapping long values

I am currently trying to work around the Material UI rating component and how to do a flex-wrap if the icons overflow the width of the parent component.
If I try to add flex-wrap: wrap to the rating component, it actually wraps the icons but the interactive functionality stops working pas the first line.
Here is a code example below to better demonstrate this:
Code Example in CodeSandbox
Is there a way to make it work with flex-wrap? If anyone could help I will very much appreciate.
I have decided that was better to build one by myself with the ability to wrap if the max value is big.
Will leave it here so someone who might have the same issue as me can use it.
CustomRating.js
import React, { useState } from 'react'
import { Tooltip } from '#mui/material'
import './CustomRating.css'
function CustomRating({ max, value, onChange, icon, emptyIcon }) {
const [innerValue, setInnerValue] = useState(value)
const checkIfIconInsideValue = (index) => {
return value >= index + 1
}
const handleMouseHover = (e, index) => {
if (e.type === 'mouseenter') {
setInnerValue(index)
return
}
setInnerValue(value - 1)
}
return (
<Tooltip title={innerValue} placement='top'>
<div className='custom-rating-main-div'>
{Array.from({ length: max }).map((elem, index) => {
return (
<div
className={`custom-rating-icon-div ${checkIfIconInsideValue(index) ? 'filled' : ''}`}
key={index}
onClick={() => onChange(index + 1)}
onMouseEnter={(e) => handleMouseHover(e, index)}
onMouseLeave={(e) => handleMouseHover(e, index)}
>
{checkIfIconInsideValue(index) || innerValue >= index ? icon : emptyIcon}
</div>
)
})}
</div>
</Tooltip>
)
}
export default CustomRating
CustomRating.css
.custom-rating-main-div {
display: flex;
flex-wrap: wrap;
}
.custom-rating-icon-div {
cursor: pointer;
}
.custom-rating-icon-div.filled > svg {
fill: #61634f
}
.custom-rating-icon-div > svg {
fill: rgba(97, 99, 79, 0.5)
}
.custom-rating-icon-div:hover > svg {
fill: #61634f;
transform: scale(1.2);
}
As you may notice this is specific to my problem but can be very easily adapted to any case.
keep in mind that this is very rough and can be updated to better follow conventions and for better performance, but for now it is my solution

How to disable the Text field name is disappearing when we moved out the input filed box in react js

I have made autocomplete features using Downshift using react js. But the problem is when I am searching for something its input field value is disappearing when I click on the outside. Here is the sample code.
import logo from './logo.svg';
import './App.css';
import React, { useState } from "react";
import Highlighter from "react-highlight-words";
import Downshift from "downshift";
import axios from 'axios';
function App() {
const [names, setnames] = useState([{
const [searchTerm, setSearchTerm] = useState('')
const [movie, setmovie] = useState([])
fetchMovies = fetchMovies.bind(this);
inputOnChange = inputOnChange.bind(this);
function inputOnChange(event) {
if (!event.target.value) {
return;
}
fetchMovies(event.target.value);
}
function downshiftOnChange(selectedMovie) {
alert(`your favourite movie is ${selectedMovie.title}`);
}
function fetchMovies(movie) {
const moviesURL = `https://api.themoviedb.org/3/search/movie?api_key=1b5adf76a72a13bad99b8fc0c68cb085&query=${movie}`;
axios.get(moviesURL).then(response => {
setmovie(response.data.results);
// this.setState({ movies: response.data.results });
});
}
return (
<Downshift
onChange={downshiftOnChange}
itemToString={item => (item ? item.title : "")}
>
{({
selectedItem,
getInputProps,
getItemProps,
highlightedIndex,
isOpen,
inputValue,
getLabelProps
}) => (
<div>
<label
style={{ marginTop: "1rem", display: "block" }}
{...getLabelProps()}
>
Choose your favourite movie
</label>{" "}
<br />
<input
{...getInputProps({
placeholder: "Search movies",
onChange: inputOnChange
})}
/>
{isOpen ? (
<div className="downshift-dropdown">
{movie
.filter(
item =>
!inputValue ||
item.title
.toLowerCase()
.includes(inputValue.toLowerCase())
)
.slice(0, 10)
.map((item, index) => (
<div
className="dropdown-item"
{...getItemProps({ key: index, index, item })}
style={{
backgroundColor:
highlightedIndex === index ? "lightgray" : "white",
fontWeight: selectedItem === item ? "bold" : "normal"
}}
>
{item.title}
</div>
))}
</div>
) : null}
</div>
)}
</Downshift>
);
}
export default App;
This is the sample code I have written. Also, when I click shift+home, it is also not working.
Problem 1: when the user clicked the outside text field value whatever I searched this is disappearing.
Problem 2: shift + home is not working also.
Anyone has any idea how to solve this problem?
when the user clicked the outside text field value whatever I searched this is disappearing.
One way you could do it is to set the stateReducer on the Downshift component:
This function will be called each time downshift sets its internal state (or calls your onStateChange handler for control props). It allows you to modify the state change that will take place which can give you fine grain control over how the component interacts with user updates without having to use Control Props. It gives you the current state and the state that will be set, and you return the state that you want to set.
state: The full current state of downshift.
changes: These are the properties that are about to change. This also has a type property which you can learn more about in the stateChangeTypes section.
function stateReducer(state, changes) {
switch (changes.type) {
case Downshift.stateChangeTypes.mouseUp:
return {
...changes,
isOpen: true,
inputValue: state.inputValue,
};
default:
return changes;
}
}
This way if you click outside the text field the dropdown will stay open and the input value won't be reset.
For a list of all state change types see the documentation here
You might also be able to get something working using the onBlur prop on the input, but I didn't get that working.

React: Slider with useEffect hook not working properly when trying to save the slider's state into local storage

I'm trying to save the state of my slider in local storage using the UseEffect hook, so the selected value in the slider doesn't get lost when the user refreshes the page. However, the slider is acting weirdly when I add this functionality.
Here is the code in the parent component:
function ParentComponent() {
const [prefState, setPrefState] = React.useState(50);
React.useEffect(() => {
const data = window.localStorage.getItem("pref_state");
if (data) {
setPrefState(JSON.parse(data));
}
}, []);
React.useEffect(() => {
window.localStorage.setItem("pref_state", JSON.stringify(prefState));
});
const handlePrefSliderChange = (event, new_value) => {
setPrefState(new_value);
};
return (
<div className={classes.root}>
<Grid item xs={12} >
<CustomizedPrefSlider
PrefSliderValues={prefState}
onPrefSliderChange={handlePrefSliderChange}
/>
</Grid>
</div>
);
}
export default ParentComponent;
Here is the code for the child component:
const PrefSlider = withStyles({
root: {
color: '#52af77',
height: 8,
padding: '13px 0',
},
track: {
height: 8,
},
rail: {
color: '#d8d8d8',
opacity: 1,
height: 8,
},
})(Slider);
export default function CustomizedPrefSlider({PrefSliderValues, onPrefSliderChange}) {
const classes = useStyles();
return (
<div>
<div className={classes.title}>
<Typography className={classes.titleFont}>
How important is this feature to you?
</Typography>
</div>
<div className={classes.root}>
<PrefSlider
aria-labelledby="discrete-slider"
value={PrefSliderValues}
onChange={onPrefSliderChange}
min={0}
max={100}
step={25}
/>
</div>
</div>
);
}
Is this the correct way of saving the state of the slider to avoid losing data when the user refreshes the page? Why am I missing some of the stylings that I added to my slider when I add this functionality?
Thanks in advance!
Doing it this way looks like it should technically work, but seems very inefficient.
I'd suggest using a custom made hook, something like useLocalStorage or #rehooks/local-storage
useLocalStorage is nice because the code is small and easy to understand, and it would shrink your code down to this:
const [prefState, setPrefState] = useLocalStorage(50);

How to handle "Cannot read property 'node' of null" in a query

I am pretty new to React/Gatsby and am doing a query with Apollo.
The thing is that if there is no title or image it'll say "Cannot read property 'node' of null". I get that because if I do not set a title or image in my headless CMS there's no data to read.
How can I make it conditional so that if 'title' is empty don't render it. Any other suggestions or tips about my code are always welcome!
Here's an example of my code
import React from "react"
import Container from "react-bootstrap/Container"
import Image from "react-bootstrap/Image"
import { useQuery, gql } from "#apollo/client"
const APOLLO_QUERY = gql`
{
posts {
nodes {
title
databaseId
content(format: RENDERED)
featuredImage {
node {
sourceUrl
}
}
}
}
}
`
const ApolloTest = () => {
const { data } = useQuery(APOLLO_QUERY)
return (
<Container>
{data &&
data.posts.nodes.map(post => {
return (
<article key={post.databaseId}>
<h3>{post.title}</h3>
<p>{post.content}</p>
<Image
src={post.featuredImage.node.sourceUrl}
alt={post.title}
style={{ width: "150px" }}
fluid
></Image>
</article>
)
})}
</Container>
)
}
export default ApolloTest
I would recommend short-circuit evaluation to first check if the information exists prior to trying to render it. A quick example is {post.title && <h3>{post.title}</h3>}, which will only render the h3 and everything inside it if post.title is truthy. You can extend this to work for the image as well:
return (
<Container>
{data?.posts.nodes.map(post => {
return (
<article key={post.databaseId}>
{post.title && <h3>{post.title}</h3>}
<p>{post.content}</p>
{post.featuredImage && <Image
src={post.featuredImage.node.sourceUrl}
alt={post.title}
style={{ width: "150px" }}
fluid
/>}
</article>
)
})}
</Container>
)

Resources