I was wondering how to get the height and width of an image if I'm rendering it react style so I can process it to flip it to portrait mode if the width is larger than the height.
Example: https://codesandbox.io/s/k9kwv0kp93
Example code:
index.js
import React from 'react';
import { render } from 'react-dom';
import Hello from './Hello';
const styles = {
fontFamily: 'sans-serif',
textAlign: 'center',
};
const App = () => (
<div style={styles}>
<Hello name="CodeSandbox" />
<h2>Start editing to see some magic happen {'\u2728'}</h2>
</div>
);
render(<App />, document.getElementById('root'));
Hello.js
import React, {Component} from 'react';
export default class Hello extends Component
{
constructor()
{
super();
this.state = {img: null}
this.get_image = this.get_image.bind(this);
}
get_image()
{
let img = <img src="http://via.placeholder.com/350x150" alt="" />;
//manipulate here maybe
this.setState({
img
})
}
render()
{
return (
<div>
<button onClick={this.get_image}>Click me</button>
test
{this.state.img}
</div>
)
}
}
I encountered the same issue, I was able to get the img height and width using ref and onLoad().
Class component version (with 'old' ref usage):
render() {
return (
<img
src='https://via.placeholder.com/150'
ref={el => this.imgEl = el}
onLoad={() => console.log(this.imgEl.naturalHeight)} // print 150
/>
)
}
Class component version (with 'new' ref):
import * as React from "react";
import ReactDOM from "react-dom";
class App extends React.Component {
imgEl = React.createRef();
render() {
return (
<img
src="https://via.placeholder.com/150"
ref={this.imgEl}
onLoad={() => console.log(this.imgEl.current.naturalHeight)} // print 150
/>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Functional component version:
import React from "react";
import ReactDOM from "react-dom";
function App() {
const imgElement = React.useRef(null);
return (
<img
src="https://via.placeholder.com/150"
ref={imgElement}
onLoad={() => console.log(imgElement.current.naturalHeight)} // print 150
/>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Also you should use img.naturalHeight
React supports a special attribute that you can attach to any component. The ref attribute takes a callback function, and the callback will be executed immediately after the component is mounted or unmounted.
When the ref attribute is used on an HTML element, the ref callback receives the underlying DOM element as its argument
Taken from: https://facebook.github.io/react/docs/refs-and-the-dom.html
class MyComponent extends React.Component {
constructor(props) {
super(props);
}
handleSize(image) {
console.log(image.offsetWidth, image.offsetHeight)
}
render() {
return React.createElement("img", {
src: "http://cdn.collider.com/wp-content/uploads/2016/07/narcos-season-2-image-5.jpg",
ref: image => {
this.handleSize(image);
},
onLoad=(image)=>this.handleSize(image);
});
}
}
ReactDOM.render(React.createElement(MyComponent, null), document.getElementById('root'))
img {
width: 200px;
height: 133px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-with-addons.min.js">
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
Related
So I am using react-to-pdf to print Html tags to PDF the button is on one component and text is on another, I don't seem to have much knowledge as to how to make the button print index.js as pdf. I am pretty sure that something is wrong in ref and imports
button.js
import React, { Component } from "react";
import Pdf from "react-to-pdf";
const ref = React.createRef();
class Button extends Component {
render() {
return (
<React.Fragment>
<Pdf targetRef={ref} filename="code-example.pdf">
{({ toPdf }) => <button onClick={toPdf}>Generate Pdf</button>}
</Pdf>
</React.Fragment>
);
}
}
export default Button;
index.js
import React, { Component } from "react";
import "./styles.css";
import Button from "./button";
const ref = React.createRef();
class Index extends Component {
render() {
return (
<React.Fragment>
<div className="App">
<div ref={ref}>
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
</div>
</div>
</React.Fragment>
);
}
}
export default Index;
ReactDOM.render(<Button />, document.getElementById("top"));
const rootElement = document.getElementById("root");
ReactDOM.render(<Index />, rootElement);
Use like this:
import React from "react";
import ReactDOM from "react-dom";
import Pdf from "react-to-pdf";
const Button = React.forwardRef((props, ref) => {
return (
<React.Fragment>
<Pdf targetRef={ref} filename="code-example.pdf">
{({ toPdf }) => <button onClick={toPdf}>Generate Pdf</button>}
</Pdf>
</React.Fragment>
);
});
const App = () => {
let docToPrint = React.createRef();
return (
<div>
<div>
<Button ref={docToPrint} />
</div>
<React.Fragment>
<div className="App">
<div
ref={docToPrint}
style={{
borderRadius: "5px",
width: "600px",
height: "400px",
margin: "0 auto",
padding: "10mm"
}}
>
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
</div>
</div>
</React.Fragment>
</div>
);
};
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Answer output: HERE
You can expose out props from the button to pass in the ref to the component you want saved to PDF. Here's a demo of a PDF button with targetRef and fileName props.
PDFButton.jsx
import React from "react";
import PropTypes from "prop-types";
import Pdf from "react-to-pdf";
// expose a targetRef prop and filename
const PDFButton = ({ children, filename, targetRef }) => (
<Pdf targetRef={targetRef} filename={filename}>
{({ toPdf }) => <button onClick={toPdf}>{children}</button>}
</Pdf>
);
PDFButton.propTypes = {
filename: PropTypes.string,
targetRef: PropTypes.any
};
PDFButton.defaultProps = {
filename: "code-example.pdf"
};
export default PDFButton;
App.js
import React, { createRef } from "react";
import PDFButton from "./PDFButton";
import "./styles.css";
export default function App() {
const pdfRef = createRef(); // create a single ref to pass to button
return (
<div ref={pdfRef} className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<p>This is a demo how to create a save to PDF button</p>
<PDFButton
fileName="awesomePDFButtonDemo.pdf"
targetRef={pdfRef}
>
Save to PDF!
</PDFButton>
</div>
);
}
I have a parent componenet, Inside this I have included a child component with props.
but When any state is changed in parent component (that doesn't related to child component) then child component re-render. I don't want this re render
on every state change. Can we stop?
import React, { useState } from "react";
import ReactDOM from "react-dom";
import Child from "./child";
import "./styles.css";
function App() {
const [any_state, setAnyState] = useState(false);
const handleClick = () => {
setAnyState(!any_state);
};
return (
<div className="App">
Parent Page ({any_state ? "true" : "false"})
<br />
<button onClick={handleClick}>Click me</button>
<Child data={"any data"} />
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
child.js
import React from "react";
function Child(props) {
console.log("child component");
return <div className="App">child Page</div>;
}
export default Child;
https://codesandbox.io/s/clever-oskar-fpxm3?fontsize=14
I don't want "child component" to be displayed in console on every state change.
You want to use React.memo for this. Read more here.
This will prevent re-renders when props did not change.
Instead of export default Child; use export default React.memo(Child); in your child.js.
import React from "react";
function Child(props) {
console.log("child component");
return <div className="App">child Page</div>;
}
export default React.memo(Child);
You gonna have to set up a Redux state
Or you just isolate the React Hook useState, make a good component destructuring :)
App.js
import React, { useState } from "react";
import ReactDOM from "react-dom";
import Child from "./child";
import Parent from "./parent"; // <--------- HERE
import "./styles.css";
function App() {
return (
<div className="App">
<Parent />
<Child data={"any data"} />
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
parent.js
function Parent() {
const [any_state, setAnyState] = useState(false);
const handleClick = () => {
setAnyState(!any_state);
};
return (
<>
Parent Page ({any_state ? "true" : "false"})
<br />
<button onClick={handleClick}>Click me</button>
</>
);
}
Here is the index.js file
import React from "react";
import ReactDOM from "react-dom";
import mobx, { observable, action, decorate } from "mobx";
import mobxReact from "mobx-react";
import "./styles.css";
const Main = mobxReact.observer(
class Main extends React.Component {
// #observable internalState = false;
constructor(props) {
super(props);
this.internalState = false;
}
toggleMenu = () => {
console.log("Toggle button");
this.internalState = !this.internalState;
};
render() {
return (
<div className="App">
<h1>Toggle State</h1>
<input type="button" onClick={this.toggleMenu} value="Toggle" />
<div style={{ paddingTop: "25px" }}>
internalState {this.internalState.toString()}{" "}
</div>
</div>
);
}
}
);
decorate(Main, {
internalState: observable,
toggleMenu: action
});
function App() {
return <Main />;
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Here is the link to the codesandbox code: https://codesandbox.io/s/k37v35vylv
Since the template of this codesandbox does not support decorator syntax, I am trying to make the Main class an observer without #observer.
I am getting this error:
The error text:
TypeError: Cannot read property 'observer' of undefined
The dependencies:
There is no default export in mobx-react package. So I suggest that you can code like this:
import {observer} from 'mobx-react'
I've a problem to integrate the theming functionality inside my next.js project who use react-jss. I tried the ThemeProvider who I've found inside the documentation.
Everytime, my front-end page refresh two times. The first times, I can see that the CSS theme is apply but fews milliseconds later, the page refresh and the theme disappear.
Do you have an idea to fix my problem? Here are my files:
_document.jsx
import React from 'react';
import Document, { Head, Main, NextScript } from 'next/document';
import {
SheetsRegistry,
JssProvider,
ThemeProvider,
} from 'react-jss';
const theme = {
colorPrimary: 'green',
};
export default class JssDocument extends Document {
static getInitialProps(ctx) {
const registry = new SheetsRegistry();
const page = ctx.renderPage(App => props => (
<ThemeProvider theme={theme}>
<JssProvider registry={registry}>
<App {...props} />
</JssProvider>
</ThemeProvider>
));
return {
...page,
registry,
};
}
render() {
return (
<html lang="en">
<Head>
<style id="server-side-styles">
{this.props.registry.toString()}
</style>
</Head>
<body>
<Main />
<NextScript />
</body>
</html>
);
}
}
index.jsx
import React from 'react';
import injectSheet from 'react-jss';
import PropTypes from 'prop-types';
const styles = theme => ({
myButton: {
backgroundColor: 'black',
color: theme.colorPrimary,
},
});
const Index = ({ classes }) => (
<div className={classes.myButton}>Welcome to Novatopo website!</div>
);
Index.propTypes = {
classes: PropTypes.shape({
myButton: PropTypes.string,
}).isRequired,
};
export default injectSheet(styles)(Index);
_app.jsx
import App from 'next/app';
export default class MyApp extends App {
componentDidMount() {
const style = document.getElementById('server-side-styles');
if (style) {
style.parentNode.removeChild(style);
}
}
}
Here a CodeSandbox to reproduce the problem: codesandbox.io/s/pyrznxkr1j
2 things you could do:
prepare a codesandbox example
use ThemeProvider inside of JssProvider
I resolved the problem. You need to integrate the ThemeProvider logic inside the _app.jsx file.
Like that:
export default class MyApp extends App {
render() {
const { Component, pageProps } = this.props;
return (
<ThemeProvider theme={theme}>
<Component {...pageProps} />
</ThemeProvider>
);
}
}
I'm trying to create a title and a textbox below it using React, ES6, Webpack and Babel. The content of the title changes/re-renders as we type inside the textbox.
There are primarily two files, Header.js and app.js
//app.js
import React from "react";
import ReactDOM from "react-dom";
import Header from "./Header/Header";
export default class App extends React.Component
{
constructor()
{
super();
this.state = ({title: "Welcome"});
}
changeTitle(newtitle)
{
this.setState({title: newtitle});
}
handleChange(e)
{
const input = e.target.value;
this.props.changeTitle(input);
}
render()
{
return(
<div>
<Header changeTitle = {this.changeTitle.bind(this)} title = {this.state.title}/>
<input onChange={this.handleChange.bind(this)} />
</div>
);
}
}
const element = document.getElementById('app');
ReactDOM.render(<App/>,element);
======================================================
//Header.js
import React from "react";
import ReactDOM from "react-dom";
export default class Header extends React.Component
{
render()
{
return(
<div>
<h1>{this.props.title}</h1>
</div>
);
}
}
If I move the handleChange(e) method and <input> tag line from app.js to Header.js then it works fine, but otherwise I get error that "this.props.changeTitle is not a function", which is inside handleChange(e) method.
You don't pass a prop to <App /> called changeTitle when you render it ReactDOM.render(<App/>,element);
It looks like you just want this.changeTitle instead of this.props.changeTitle
Theres no need to pass the function changeTitle() to the <Header/> just have handleChange() call this.setState().
handleChange(e)
{
const input = e.target.value;
this.setState({title: input});
}
render()
{
return(
<div>
<Header title = {this.state.title}/>
<input onChange={this.handleChange.bind(this)} />
</div>
);
}
React will rerender <App/> which in turn will rerender() <Header/>