I'm beginner on React, and trying to learn and improve, here i have a button which is needed to be clicked and after that should appear bunch of numbers like this 1:1 1:2 1:3, but here i seem to have a problem, my button does not appear, just numbers from URL appears, and i also have css to my button which is not working either when refreshing the page css works just for 1 second then disappear and im not getting any error message...
Here is the code:
import React, { Component } from 'react'
class Button extends Component {
componentWillMount() {
var proxyurl = "https://cors-anywhere.herokuapp.com/";
var url = "http://*****.******.com/numbers.txt";
fetch(proxyurl + url) // https://cors-anywhere.herokuapp.com/https://example.com
.then(response => response.text())
.then(contents => document.write(contents))
}
render() {
return (
<div className="whole">
<button onClick={this.componentWillMount} >Increment</button>
</div>
)
}
}
export default Button;
.whole {
background-color: blue;
color: red;
margin: 50px 0;
padding: 0px;
text-align: center;
}
#root {
white-space: pre;
}
english is not my mother language so sorry for mistakes.
componentWillMount is a lifecycle event of the component and shouldn't be used like this (also it is recommended that componentWillMount is no longer used).
If you want the button to retrieve data you need to create a new function and assign it to the onClick prop of the button. eg:
handleClick = () => {
var proxyurl = "https://cors-anywhere.herokuapp.com/";
// more code
.then(contents => this.setState({ responseText: contents }))
}
render() {
return (
<div className="whole">
<button onClick={this.handleClick}>Increment</button>
</div>
<div>{this.state.responseText}</div>
);
}
Related
Im beginner on Reactjs and trying to learn and improve, here i have code where is < h1 >test< / h1 > and under this should appear numbers under each other like this 1:1 1:2 1:3, but css does not seem to work with it, i get numbers but without css and i dont get any error message either... is here something wrong ? the code :
import React, { Component } from 'react'
class Button extends Component {
state = {}
button = () => {
const proxyurl = "https://cors-anywhere.herokuapp.com/";
const url = "http://*****.*****.com/numbers.txt";
fetch(proxyurl + url)
.then(response => response.text())
.then(contents => document.write(contents))
}
render() {
return (
<div >
<h1>test</h1>
<div style={{ color: 'red' }}>{this.button()}
</div>
</div >
);
}
}
export default Button;
css:
body {
background: url('***.png');
color:red;
margin:50px 0;
padding:0px;
text-align:center;
}
#root {
white-space: pre;
}
Your render function should be pure, see https://reactjs.org/docs/react-component.html#render:
The render() function should be pure, meaning that it does not modify component state, it returns the same result each time it’s invoked, and it does not directly interact with the browser.
Your render function contains a call to this.button. So every time your component re-renders, a fetch request is made when it seems this should only be called once. As the docs suggest, move this logic into componentDidMount.
Now, onto your actual problem. You are calling document.write, and it seems you don't understand how this works. Document.write will remove all event listeners from the page and replace all content within body with the argument you supplied. Assuming you had a root element with an ID of root (<div id="root">...</div>), that will have been removed after your call to document.write; so your CSS #root selector will no longer point to an existing element.
Instead of using document.write, set the content on your component's state and render that:
import React, { Component } from "react";
export default class Button extends Component {
state = {
contents: null
};
componentDidMount() {
const proxyurl = "https://cors-anywhere.herokuapp.com/";
const url = "http://*****.*****.com/numbers.txt";
fetch(proxyurl + url)
.then(response => response.text())
.then(contents => this.setState({ contents }));
}
render() {
return (
<div>
<h1>test</h1>
<div style={{ whiteSpace: "pre" }}>{this.state.contents}</div>
</div>
);
}
}
If you're using React, you should have no reason to call document.write, even if you're doing it for testing or you're trying to implement some sort of page reload / turbolinks feature–there are much better alternatives.
ImagesUpload.jsx --> the Presentational component
deleteImageWarning.jsx --> the Notifications component
index.js --> where I exported the deleteImageWarning function
The goal
I want to include a notification or popup in my React app that alerts the user and gives them the choice to either cancel or confirm an action, in this case, deleting an image attached to a job sheet. This notification should be triggered when the user clicks the Delete button located next to the image that has been attached to the page.
Where to look for the issue
What I wrote (please have a look below) is not working whatsoever. I feel there is something wrong with the validateBeforeDelete function; I just wanted to have something that returns the notification function with the right values in the DOM. In addition, I am missing what to write in the Content section in the deleteImageWarning component.
Brief overview
To give you an idea, the button's delete functionality was working perfectly fine prior to working on the notification. There is a container for the ImagesUpload file, therefore, we could state that the ImagesUpload.jsx file is the Presentational Component and there is a ImagesUploadContainer.jsx file that acts as the Container Component for the Presentational Component.
The issue
The problem is that I don't know how to pass the delete function that I declared in the ImagesUpload.jsx file to the deleteImageWarning.jsx component. And that's surely what I am missing in the Content constant of my deleteImageWarning component. Does it have anything to do with the constants declared in my render() function?
ImagesUpload.jsx
//importing the deleteImageWarning function
import {
deleteImageWarning,
} from '../common/notifications';
//this is the function that deletes the image with the required values
async handleDeleteImage (jobsheetId, imageId) {
this.props.deleteImage({jobsheetId: jobsheetId, imageId: imageId});
}
//this is a validate function that is supposed to trigger the deleteImageWarning function
validateBeforeDelete = (jobsheetId, imageId) => {
return deleteImageWarning(this.notificationDOMRef.current, () => this.handleDeleteImage(jobsheetId, imageId));
}
render() {
const { ... } = this.props;
const { ... } = this.state;
return (
//TO BE AWARE! the following delete button with an onClick function has been written using React final form's syntax
...
<StyledSectionColRight>
<Button red type="button" onClick={() => this.validateBeforeDelete(id, image.id)}>Delete</Button>
</StyledSectionColRight>
...
);
}
export default ImagesUpload;
index.js
(Nothing really important, just in case someone thinks the error is due to not exporting deleteImageWarning)
//deleteImageWarning included in the index.js file
export { default as deleteImageWarning } from './deleteImageWarning';
deleteImageWarning.jsx
import React from 'react';
import styled from 'styled-components';
import { Button, ButtonInverted } from '../button';
const StyledNotification = styled.div`
background: var(--white);
padding: var(--spacer-m);
`;
const StyledMessage = styled.p`
font-size: var(--font-s);
line-height: var(--lineHeight-s);
margin: 0 0 var(--spacer-l) 0;
`;
const Content = ({ ????? }) => (
<StyledNotification>
<StyledMessage>
Are you sure you want to delete this image? This process cannot be undone.
</StyledMessage>
<Button type="button" red onClick={?????}>Confirm</Button>
<ButtonInverted type="button">Cancel</ButtonInverted>
</StyledNotification>
);
const deleteImageWarning = (node, ?????) => {
node.addNotification({
content: <Content ?????={?????} />,
type: "info",
title: "",
message: "",
insert: "top",
container: "top-center",
animationIn: ["animated", "fadeIn"],
animationOut: ["animated", "fadeOut"],
dismissable: { click: true },
width: 400
});
}
export default deleteImageWarning;
To make it super obvious, I have added a few question marks in the code to highlight where I don't know what to write.
I think your way of thinking is somewhat (not to be harsh) wrong, please correct me if I am missunderstanding. Where should the Content be rendered? I don't see a place where it would be.
What I would do is make a new Component (instead of a function) and render it only when a flag in the state (e.g. state = { ... , isdeleting = true }) turns true. You might also store the information of the image to be deletet in the state and pass it down to the Component:
//[prev. Code in ImagesUpload.jsx]
{ this.state.isdeleting ? <DeletImgWaring handleDeleteImage = {this.handleDeleteImage} imgInformation={//e.g. this.state.imgToBeDelInfo}
In this way you think more in component-based. And you can reuse the DeletImgWaring-Component somewhere else.
Does this help?
Regards
I am testing out a simple next.js react app, although an error is showing up when I try to access it at localhost:300. On line 46 of my news.js page, I am trying to test if state.articles is empty then copy props to it, although next.js is telling me .length is undefined. Does anyone know why .length is undefined?
Error is as follows; TypeError: Cannot read property 'length' of undefined
any help is apprecaited
// This is the Link API
import Link from 'next/link';
import fetch from 'isomorphic-unfetch';
//import SearchForm from './components/SearchForm';
const apiKey = 'API-KEY';
const source = 'the-irish-times';
//build the url which will be sued to get the data
const url = `https://newsapi.org/v2/top-headlines?
country=ie&category=sports&apiKey=${apiKey}`;
//getNews(url) is an async method which fetchs and
returns data or and erroe
//from WWW Api
async function getNews(url){
//try fetch and catch any errors
try{
//make async call
const res = await fetch(url);
//get json data when it arrives
const data = await res.json();
//return json data
return(data);
} catch (error){
return(error);
}
}
// the news page definied as an ES6 Class
export default class News extends React.Component{
//constructor
//receive props and initialise state properties
constructor(props){
super(props)
this.state = {
newsSource: "",
url: "",
atricles: []
}
} // end constructor
// render() method generates the page
render() {
//if state.articles is empty copy props to it
**** THIS LINE
if(this.state.articles.length == 0){
this.state.articles = this.props.articles;
}
return (
<div>
{ /* display a title based on source */}
<h3>{this.state.newsSource.split("-").join(" ")}
</h3>
<div>
{ /*iterate through artiles using array map */}
{ /* display author, publishedAT, image, desc and
content */}
{ /* for each story also a link for more */}
{this.state.articles.map((article, index) => (
<section key = {index}>
<h3>{article.title}</h3>
<p className="author">{article.author}
{article.publishedAt}</p>
<img src={article.urlToImage} alt="artile
image" className="img-article"></img>
<p>{article.description}</p>
<p>{article.content}</p>
<p><Link href="/story"> <a>Read mor</a> </Link>
</p>
<p onClick = {this.test}>click..</p>
</section>
))}
</div>
<style jsx>{`
section {
width: 50%;
border: 1px solid grey;
background-color: rgb(240, 248, 255);
padding: 1em;
margin: 1em;
}
.author {
font-style: italic;
font-size: 0.8em;
}
.img-article {
max-width: 50%;
}
`}</style>
</div>
);
}//end render
}
//get initial data on server side using an AJAX call
// this will initialise the 'props' for the news page
async function getInitialProps(response){
//build the url which will be used to get the data
const initUrl = `https://newsapi.org/v2/top-
headlines?
sources=${defaultNewsSource}&apiKey=${apiKey}`;
//get news data from tje api url
const data = await getNews(initUrl);
//if the result contains an articles array then it is
good so return articles
if(Array.isArray(data.articles)) {
return {
articles: data.articles
}
}
// otherwise it contains an error, log and redirect
to error page
else {
console.error(data)
if(response) {
response.statusCode = 400
response.end(data.message);
}
}
} // end initial props
A couple problems:
1.) Mistyped state property name
I believe you meant articles not atricles.
Should be
this.state = {
newsSource: "",
url: "",
articles: []
}
not
this.state = {
newsSource: "",
url: "",
atricles: []
}
2.) Mutating immutable React state
In React we change the state with setState(). Keep in mind this is an asynchronous action and since you're calling it in the render function it will likely not appear until the next render.
if(this.state.articles.length == 0){
this.setState({ articles: this.props.articles });
}
class Application extends React.Component {
constructor(props) {
super(props);
this.state = {
articles: []
};
}
render() {
if(this.state.articles.length == 0){
return (<div>Articles has no length</div>);
}
return (
<div>
Articles has a length.
</div>
);
}
}
// Render it
ReactDOM.render(
<Application/>,
document.getElementById("react")
);
<div id="react"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
a bit new to react.
I used the create react app https://github.com/facebook/create-react-app
to start a new react project.
the full code is here. https://github.com/bryandellinger/reactswitch/tree/master/src
I am trying to get the background color of a selected element to change and the text to become bold but it appears the class is never added not sure what I am doing wrong.
Switch.js
import React, { PropTypes } from 'react';
import styles from './Switch.css';
const CREDITCARD = 'Creditcard';
const BTC = 'Bitcoin';
const Choice = function (props) {
const cssClasses = [];
if (props.active) {
// <-- check props, not state
cssClasses.push(styles.active);
}
return (
<div
onClick={props.onClick}
className={cssClasses}
>
{props.label} {/* <-- allow any label */}
</div>
);
};
class Switch extends React.Component {
state = {
payMethod: BTC,
};
select = (choice) => {
return (evt) => {
this.setState({
payMethod: choice,
});
};
};
render() {
return (
<div className='switch'>
<Choice
onClick={this.select(CREDITCARD)}
active={this.state.payMethod === CREDITCARD}
label='Pay with Creditcard'
/>
<Choice
onClick={this.select(BTC)}
active={this.state.payMethod === BTC}
label='Pay with Bitcoin'
/>
Paying with: {this.state.payMethod}
</div>
);
}
}
export default Switch;
and Switch.css
.active {
background-color: #4619eb;
font-weight: bold;
}
it appears the active class from switch.css never gets added on the onclick event. not sure what I am missing.
Because of the way webpack is configured in CRA, you need to write your css like this:
:local(.active) {
background-color: #4619eb;
font-weight: bold;
}
CRA only supports importing the whole CSS file directly out of the box. So instead of importing the CSS file as a component, you would do:
import './Switch.css';
CRA docs for adding a stylesheet: https://github.com/facebook/create-react-app/blob/master/packages/react-scripts/template/README.md#adding-a-stylesheet
Also, the className property should be a string with class names separated with a while space. If you want to set the class name dynamically, check out classnames: https://github.com/JedWatson/classnames.
I have a ref on a component I am converting over to a styled component in my app. The ref is used to access the offsetHeight and scrollHeight properties on the raw html element of the component. Once I switched this component to a styled component, the ref now points to the styled component instead of the raw html element, and I'm unsure how to reference the base element. Can this be done?
example:
const TextArea = styled.textarea`
display: block;
margin: 0 0 0 18%;
padding: 4px 6px;
width: 64%;
font-size: 1rem;
color: #111;`;
export default class Input extends Component {
componentDidMount() {
const height = this.textInput.scrollHeight;
// do something....
}
render() {
return (
<div>
<TextArea
ref={(input) => this.textInput = input}
></TextArea>
</div>
);
}
}
Passing ref to a styled component will give you a ref to the styled-components wrapper, not the DOM node. To get a ref to actual DOM node pass the innerRef prop. (see the docs)
This is what you need to do:
const TextArea = styled.textarea``;
export default class Input extends Component {
componentDidMount() {
const height = this.textInput.scrollHeight;
// do something....
}
render() {
return (
<div>
<TextArea
innerRef={(input) => this.textInput = input}
></TextArea>
</div>
);
}
}
Yes it can be done. You can access raw html using ReactDOM.findDOMNode(). However, bear in mind that the use of this method is discouraged. You can read more about this in the referenced page.