Steven
Steven

Reputation: 11

React: how to change the style property of one JSX element based on another?

I'm trying to do some styling with react. I've got a results page, and I want my results cards to stretch (a bit) to fill each line. To do that I'm using...

let body = {
  display: "flex",
  margin: "0% 10%",
  flexWrap: "wrap",
};

and...

let card = {
    fontSize: "90%", 
    flexBasis: "15rem",
    minWidth: "10rem",
    flexShrink: "1",
    flexGrow: "1",
}

My issue is that I also want all the results cards to be the same size. Normally, I'd think about using jQuery for this, but I'm using React and that's a bit awkward.

So, what I'm trying to do is pass the width information of the first results card (child component) back to the results page (parent component) with a callback function. Then, I intend to pass a "maxWidth" property to the other results cards using props. Note: this works, in the sense that I can pass width information back to the parent and I can style a results card using props.

The problem is that when I try to assign the width information to the props of one of the other results cards, it is undefined. I suspect this is because you can't update the state and take information from the state while a JSX element is rendering...

Any ideas about how I can achieve what I want? Any ideas about how I can somehow pause the render in order to update the state?

All the best

Parent Component

import React from 'react';
import ReactDOM from 'react-dom';
import Card from './Card.js';

class Body extends React.Component {
constructor(props){
  super(props);
  this.state = {
  };
  this.cardWidth = function (width) {
    this.state.cardWidth = width;
    console.log(this.state.cardWidth);
  }.bind(this);
};
render() {
  return (
    <div className="body" style={body}>
      <Card cardWidth={this.cardWidth}/>
      <Card style={{maxWidth:`${this.state.cardWidth}`}}/>
      <Card style={{maxWidth:`${this.state.cardWidth}`}}/>
    </div>
  );
};
};

let body = {
  display: "flex",
  margin: "0% 10%",
  flexWrap: "wrap",
};

export default Body;

Child Component

import React from 'react';
import ReactDOM from 'react-dom';

class Card extends React.Component {
constructor(props){
    super(props);
    this.state = {
    };
    this.cardref = React.createRef();
};
componentDidMount() {
    if (this.props.cardWidth) {
        this.props.cardWidth(this.cardref.current.offsetWidth);
    };
};
render() {
    return (
        <div className="card" style={(this.props.style)?(Object.assign({}, this.props.style, card)): card} ref={this.cardref}>
            <div className="card-body">
                <h5 className="card-title" style={{fontSize: "100%"}}>Card title</h5>
                <p className="card-text" style={pText}>Some quick example text to build on the card title and make up the bulk of the card's content.</p>
                <a href="#" className="btn btn-primary" style={{fontSize: "80%"}}>Go somewhere</a>
            </div>
        </div>
    );
};
};

let card = {
    fontSize: "90%", 
    flexBasis: "15rem",
    minWidth: "10rem",
    // maxWidth: "15rem",
    flexShrink: "1",
    flexGrow: "1",
}

let pText = {
    display: "block",
    textOverflow: "ellipsis",
    overflow: "hidden",
    height: "4rem",
    fontSize: "80%"
};

export default Card;

Upvotes: 0

Views: 3253

Answers (2)

Steven
Steven

Reputation: 11

Turns out I'd missed out px after the maxWidth property value. Now I have the problem that I need it to re-render on a view port resize event.

Desired behavior

Upvotes: 1

Maddo
Maddo

Reputation: 185

To make all the cards the same size, within a given space, can use flex-grow. For example if you set flex-grow: 1 on all your cards then they will all grow to fill the extra space evenly. There is a nice diagram on this page also if you look for the 'flex-grow' heading.

Upvotes: 0

Related Questions