I am new to React, and am trying to call a function which acts as a component, but returns two values, one called 'render' which just returns a component wrapped in a div, and another called sliderVal, which is an internal state value of that slider. Below is code from MySlider.js
function MySlider(props) {
const [sliderVal, setSliderVal] = useState(1);
return{
render:(
<div>
<Grid container justify = "center">
<Box sx={{ width: 250 }}>
<Typography id="input-slider" gutterBottom>
{props}
</Typography>
<Slider
defaultValue={1}
valueLabelDisplay="auto"
step={1}
value={sliderVal}
marks
min={1}
max={10}
onChange={(_, newValue) => setSliderVal(newValue)}
/>
</Box>
</Grid>
</div>
),
sliderVal
}
In my App.js, I am using the following code to render two sliders, and pass their values into another component.
var {render, sliderVal} = MySlider("Number of Paragraphs");
var {render1, sliderVal1} = MySlider("Number of Words");
The first one works just fine, I can use {render} to render the slider, and {sliderVal} to access its value and pass into another component. However the 2nd one does not work and nothing renders. When I console.log render1 and sliderVal1, they are both undefined. Any insight is greatly appreciated!
The 2nd change to:
var {render:render1, sliderVal:sliderVal1} = MySlider("Number of Words");
Related
I have a status in the dashboard and want to change its status. I need when I click it, the state will change its value.
My component
<MenuItem>
<Button
fullWidth
onClick={handleChangeStatus}
>
<Typography value={"pending"} sx={{ color: "#488C6E" }}>
pending
</Typography>
</Button>
</MenuItem>
State and function
const [changeStatus, setChangeStatus] = useState(data.status);
const handleChangeStatus = (e) => {
console.log(e.target);
setChangeStatus(e.target.value);
};
The main problem is that the console looks e.target. For example, if I click it, the console shows:
<p class="MuiTypography-root MuiTypography-body1 css-rzm8ko-MuiTypography-root" value="pending">pending</p>
but if I write e.target.value, it gives undefined
You cant use "value" prop in Typography. Please click here link to see which props you can use in Typography.
I didn't understand what you want to do. But you can try this:
<Typography sx={{ color: "#488C6E" }}>
{pending}
</Typography>
My component will not display on the page. There are no errors or any other warnings/messages. I console log the value of gameData and all the data is as it should be. Here's the exported function:
export default function AllGameDeals( gameData ){
const dealArr = new Array()
const deals = () => {
gameData.deals.map((deal) => {
const imageSrc = `https://www.cheapshark.com/img/stores/icons/${(parseInt(deal.storeID)-1)}.png`
deal.imageSrc = imageSrc
dealArr.push(deal)
})
return dealArr
}
deals()
return (
<div>
{dealArr.forEach(gameDeal => (
<Box
key={gameDeal.dealID}
display={{ md: "flex" }}
boxShadow="dark-lg"
p={4}
>
<Box flexShrink={0}>
<Image borderRadius="lg"
width={{ md: 40 }}
height={{ md: 20 }}
src={gameData.info.thumb}
alt={gameData.info.title} />
</Box>
<Box>
<Image
src={gameDeal.imageSrc}
alt={gameDeal.storeID} />
</Box>
<Box>
<Text>{gameDeal.price}</Text>
</Box>
</Box>
))}
</div>
)
}
I feel like I am missing something very obvious...
Try changing from dealArr.forEach to dealArr.map.
The reason is that .forEach returns nothing, but .map returns an array.
You should be using .map instead of .forEach because .forEach doesn't actually return a value
Other possible improvements:
Use useEffect to fetch data on mount of the component (instead of fetching everytime)
Use useState to "persist" your state within the component
I have a storybook project and created a new custom component. I used a hover state and when I hover the component, it updates its className and it just works fine. Named: ProductSize
And then, I created a new component to group the ProductSize component and named it as ProductSizeGroup and grouped them by the Json inside the ProductSizeGroup stories.
And here is the final product screen:
Here, I want to see the sizes when I hover the boxes. But, it shows me all the sizes all alone like this. Apparently, I only want to see XSmall when I hover to XS, Small in S etc..:
Edit: Many people asked for the coding side and that is here - a live coding example:
https://codesandbox.io/s/usestateissue-10l4l
So, how to solve it?
Here is the ProductSizeGroup component code displaying the ProductSize items and hover-triggered sizes
const ProductSizeGroup: React.FC<IProductSizeGroupProps> = (props) => {
const { ProductSizes } = props;
const [inHover, setHover] = useState(false);
return (
<Box style={{ width: "100%" }}>
<Typography>
{" "}
Size:
{ProductSizes.map((products: any) =>
inHover ? products.name : undefined
)}
</Typography>
<Box display="flex" justifyContent="flex-start" p={1} m={1}>
{ProductSizes.map((products: any) => (
<Box
onMouseEnter={() => setHover(true)}
onMouseLeave={() => setHover(false)}
>
<ProductSize
inStock={products.inStock}
sizeText={products.sizeText}
name={products.name}
/>
</Box>
))}
</Box>
</Box>
);
};
The issue is that you're displaying the size via the following
Size:
{ProductSizes.map((products: any) =>
inHover ? products.name : undefined
)}
where inHover is simply a Boolean value. So this will either show all name values or nothing.
I think what would work better is something like the following where you set the hovered state to the value you want and simply display it
const [hovered, setHovered] = useState<string | undefined>();
return (
<!-- snip -->
<Typography>Size: {hovered}</Typography>
<!-- snip -->
{ProductSizes.map(product => (
<Box
onMouseEnter={() => setHovered(product.name)}
onMouseLeave={() => setHovered(undefined)}
>
<!-- etc -->
</Box>
))}
)
Take note that I've also removed some of your any typings in the sandbox.
In order to handle states, you can use the react context provider: https://reactjs.org/docs/context.html or react redux https://react-redux.js.org/.
Depending on how many states you have and what you want to do with them you can choose one of the two. React-redux loads only the states you need, it is faster, but it has a specific structure that you need to follow. It is more complex at the beginning, but you can easier handle multiple states.
Context provider is already installed with react, it is easier to set up, but it is slower since it loads all states on each page load.
I created a basic component such as:
export default (props) => (
<TouchableOpacity {...props} style={styles.button}>
{props.title && <Text style={styles.text}>{props.title}</Text>}
{props.icon && <Icon name={props.icon} />}
</TouchableOpacity>
);
I can then call it with <Component title="Home" icon="home" /> for instance.
The problem is that passing {...props} to TouchableOpacity generate errors because it does not recognize title nor icon properly.
For instance:
JSON value 'Home' of type NSString cannot be converted to...
Is there a way to filter props so that I only pass valid ones for TouchableOpacity?
Transferring Props
Sometimes it's fragile and tedious to pass every property along. In that case you can use destructuring assignment with rest properties to extract a set of unknown properties.
List out all the properties that you would like to consume, followed by ...other.
var { checked, ...other } = props;
This ensures that you pass down all the props EXCEPT the ones you're
consuming yourself.
function FancyCheckbox(props) {
var { checked, ...other } = props;
var fancyClass = checked ? 'FancyChecked' : 'FancyUnchecked';
// `other` contains { onClick: console.log } but not the checked property
return (
<div {...other} className={fancyClass} />
);
}
ReactDOM.render(
<FancyCheckbox checked={true} onClick={console.log.bind(console)}>
Hello world!
</FancyCheckbox>,
document.getElementById('example')
);
Like Paul Mcloughlin, I would recommend using object destructuring along with a rest parameter. You can destructure your props object directly in your function parameters like so:
({title, icon, ...remainingProps}) => (...)
This extracts the title and icon props from your props object and passes the rest as remainingProps.
Your complete component would be:
export default ({title, icon, ...remainingProps}) => (
<TouchableOpacity {...remainingProps} style={styles.button}>
{title && <Text style={styles.text}>{title}</Text>}
{icon && <Icon name={icon} />}
</TouchableOpacity>
);
I wonder how I can access my props item in my doorsItem component. My code in the parent is this:
const doors = this.props.doors.data.map(item => <DoorsItem item={item} />)
My DoorsItem component looked like this before:
const DoorsItem = ({ item, customer }) =>
<Grid>
<Row key={item._id}>
<Col style={{ width: '100%' }}>
<ul className="door-list">
<li className="door-flex-container">
<div className="door-flex-item-1">
<h4 className="title-text-container">
{item.address.street} // Can use 'item' here
But I wanted to connect it with redux so I ended up with this:
class DoorsItem extends Component {
render() {
return (
<Grid>
<Row>
<Col style={{ width: '100%' }}>
<ul className="door-list">
<li className="door-flex-container">
<div className="door-flex-item-1">
<h4 className="title-text-container">
{/* How can I use it here? */}
</h4>
</div>
So I was wondering what’s the best way to access the item props in my new coded component?
Thanks for reading and sorry for the nooby question!
When you're doing <DoorsItem item={item} />, you're assigning the item prop, which means that within this component you can use it like this.props.item or even better const { item } = this.props; and use the item local variable later. So for example:
const { item } = this.props;
return <span>this is the {item} you're looking for</span>
More information about that on the official documentation.
Usually, when using class based components, we should define the propTypes and defaultProps. This gives us a better understanding of the class-based component's props to use and provides validation for props to be inserted. More information here (warning: moved to a separate package since React v15.5).
Finally, you can use context, which is not the recommended way but sometimes can be helpful.