While the answer above is valid, it's always good to write modular code and keep your react components stateless (without having state variables). The following code shows a better approach to your problem:
import React from "react";
import listUnitItem from "./listUnitItem.scss";
//Number formatting
const numeral = require('numeral');
export default class ListUnitItem extends React.Component {
// Save this method in some Utils class where you can access from other components.
getFormattedNumber(number){
//format numbers greater than 1000
if (number > 1000) {
//only format number
number = numeral(number).format('0.0a');
}
return number
}
render() {
return(
<li className="list-unit-item col-sm-2">
<span className="unit-item-number">{this.getFormattedNumber(this.props.number)}</span>
<span className="unit-item-title">{this.props.title}</span>
</li>
)
}
}
I hope this helps!
Answer from Gui Herzog on Stack OverflowWhile the answer above is valid, it's always good to write modular code and keep your react components stateless (without having state variables). The following code shows a better approach to your problem:
import React from "react";
import listUnitItem from "./listUnitItem.scss";
//Number formatting
const numeral = require('numeral');
export default class ListUnitItem extends React.Component {
// Save this method in some Utils class where you can access from other components.
getFormattedNumber(number){
//format numbers greater than 1000
if (number > 1000) {
//only format number
number = numeral(number).format('0.0a');
}
return number
}
render() {
return(
<li className="list-unit-item col-sm-2">
<span className="unit-item-number">{this.getFormattedNumber(this.props.number)}</span>
<span className="unit-item-title">{this.props.title}</span>
</li>
)
}
}
I hope this helps!
I would personally put this into state using this.setState({}) in the componentWillMount function.
Something like
export default class ListUnitItem extends React.Component {
componentWillMount() {
let number = this.props.number;
if(number > 1000) {
number = numeral(number).format('0.0a');
}
this.setState({number})
}
render() {
return(
<li className="list-unit-item col-sm-2">
<span className="unit-item-number">{this.state.number}</span>
<span className="unit-item-title">{this.props.title}</span>
</li>
)
}
}
I was looking at this tutorial (the part about not using let, var or const will make the variable available outside of the function and uses the variables Video and Length )
https://tutorial.eyehunts.com/js/how-to-access-variable-outside-function-in-javascript-code/
I get the error Cannot find name 'outside' like it wants me to declare outside first? In the example in the tutorial they don't declare it and it says it works.
Here is my code:
const Home: React.FC = () => {
const printCurrentPosition = async () => {
outside = await Geolocation.getCurrentPosition();
console.log('Current position:', outside)
}
useEffect(() => {
printCurrentPosition()
}, [])
return (
<IonPage>
<IonHeader>
<IonToolbar>
<IonTitle>Blank</IonTitle>
</IonToolbar>
</IonHeader>
<IonContent fullscreen>
<IonHeader collapse="condense">
<IonToolbar>
<IonTitle size="large">Blank</IonTitle>
</IonToolbar>
</IonHeader>
<IonText>
Hello {outside}
</IonText>
<ExploreContainer />
</IonContent>
</IonPage>
);
};
export default Home;
I see two options here.
- Assign the variables to the
windowobject - Use environment variables
Using the window object
To use the window object, declare the variable as
myVar = 'someString'
or
window.myVar = 'someString'
In both cases you'll access the variable within React with window.myVar. Here's a quick example:
class App extends React.Component {
render() {
return (
<div>
<h1>Hello, React and ES6!</h1>
<p>Let's play. :)</p>
<p>{window.myVar}</p>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("app"));
html,
body {
height: 100%;
}
body {
display: flex;
justify-content: center;
align-items: center;
font-family: Helvetica Neue;
}
<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>
<div id="app"></div>
<script>
window.myVar = 'someString2'
</script>
Using environment variables
The Create React App build allows for environment variables to be used within the app. To add an environment variable create a .env file in the root of your project, then add the appropriate variables and prefix the variable name with REACT_APP_. For example:
REACT_APP_MYVAR = "someString"
In the app these variables can be accessed within your components with {process.env.REACT_APP_MYVAR}, or within the HTML with %REACT_APP_MYVAR%.
The EcmaScript 6 introduced block-scope variables and constants declared by let resp. const.
In contrast to the "old style" declaration of variable by var the visibility of such variable resp. constant is limited to actual block.
The scope of constant const1 (resp. const2) is therefore limited only to the code inside the script tag.
To be able to access the const1 (resp. const2) from another script tag you would need to change its visibility. This can be achieved either by declaring it by var or by assigning its value to a variable declared by var.
E.g.:
<script type="text/javascript">
const const1 = "1234";
const const2 = "5678";
var visibleConst1 = const1;
</script>
Later in your React application you can read it from window.visibleConst1.
You can simply define your testing variable outside of your function:
let testing;
function someFunc(someInput) {
testing = "some data";
}
const global = testing;
Or you can return it inside the function:
function someOtherFunc(input){
let testing = "some data"
return testing;
}
const testing = someOtherFunc("some input");
But since your function is a reducer it really should not cause any side-effects which is exactly what you'r trying to do. Updating your question with more explanation might help find other alternative to what you are trying to reach.
I suggest you should use states
export default class App extends Component {
constructor(props) {
super(props);
}
state = {
testing:null
};}
I have been using something like:
export default class SomeComponent extends Component { ... }
let size;
// or
const styling = { backgroundColor: 'rgb(0,0,0)' }but the idea behind it seems a little vague to me. From what little I understand of scopes and closures I understand that both size and styling are considered globals, or at least within the file. When the file is exported I have assumed the globals are also attached to the module in some form or another, what is that form? What are the main differences between
import { styling } from './SomeComponent'assuming I exported the const. Is it more private access? What value or should I ask what does 'let size' belong to if it is assigned a value within a component ?
Is there a difference than something like
setStyling() {
return {
backgroundColor: 'rgb(0,0,0)'
}
}
// somewhere in the component
<div style={this.setStyling.bind(this)} />or is this all syntactic sugar?
If you export a variable you can import it into another file. So if you dont explicitly export it, it's private to the module it's defined in.
export const myVar; is public and can be imported
const myPrivateVar; is private and cannot be imported used directly or referenced in anyway.
From what little I understand of scopes and closures I understand that both size and styling are considered globals, or at least within the file.
The module is created by putting a closure around the file. Like (function(){ })(); Nothing within the file is strictly global. All of the variables are rewritten to look like var styling = {} and var size; So once the function closure is wrapped around them, they're tied to that scope alone.
Export basically hoists part of the code outside of the function. So it compiles to something like:
module = {}
module.exports.styling = { .... }
(function(){})(module.exports.styling);
Assuming I exported the const. Is it more private access?
No now styling is part of the public interface of the module.
What value or should I ask what does 'let size' belong to if it is assigned a value within a component ?
What?
is this all syntactic sugar?
Yep. That's why you can cross compile it down to regular ES5 easily. If you have a language which begun with a non-class style, then classes/modules will always be syntactic sugar due to backwards compatibility. C++ basically does this.
If classes/modules were going to be 'real' parts of the AST, then it'd break backwards compatibility... and its really unnecessary to do so.
You're using class programming on your react aplication, so you must do somenthing like this
import axios from 'axios'
class App extends Component {
constructor(props){
super(props);
this.state = {data: []}
}
componentDidMount(){
axios.get("https://ghibliapi.herokuapp.com/films")
.then(response =>{
this.setState({data: response.data});
})
.catch(function(error){
console.log(error)
})
}
componentDidUpdate(){
axios.get("https://ghibliapi.herokuapp.com/films")
.then(response =>{
this.setState({data: response.data});
})
.catch(function(error){
console.log(error)
})
}
render() {
return (
<div>
{data.map(data=> (
//logic to render the api's data
))}
</div>
)
}
}
This is how to do it
import React, { useEffect, useState } from "react";
export default function App() {
const [readData, writeData] = useState();
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/todos/1")
.then((response) => response.json())
.then((json) => writeData(json));
}, []);
return (
<>
<div>title: {readData.title}</div>
<div>completed: {String(readData.completed)}</div>
</>
);
}
Sandbox
I struggled with this exact question when I was first dealing with async code.
If you have async code in React the formula is simple. Have some state, when the async code runs, update the state and the changes should be reflected in your jsx.
You can do like this:
class Countdown extends React.Component{
constructor() {
super();
//set the initial state
this.state = { count: 10 };
}
//function to change the state
changeCount(num){
this.setState({count:num});
}
render(){
return(
<div>
<button onClick={()=>begin(this.changeCount.bind(this), this.state.count)}>start</button>
<button>pause</button>
<button>continue</button>
<p>{this.state.count}</p>
</div>
);
}
};
//callback function to change the state in component
//c is the initial count in state
const begin=(fun, c)=>{
let count = c;
const timer = setInterval(countdown,1000);
function countdown(){
count=count-1
if (count<0){
clearInterval(timer);
return;
}
fun(count)
console.log(count)
}
}
ReactDOM.render(<Countdown/>, document.getElementById('example'));
working code here
Why not declare the begin inside the react component. You will also need to update the state when the count down begins. I recommend you take a look at https://reactjs.org/tutorial/tutorial.html.
TodoComponent
import React from 'react';
import ReactDom from 'react-dom';
import TodoItem from './todoItem';
class TodoComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
todos: ["clean up", "walk doggo", "take nap"]
};
}
handleDelete(item){
let todos = this.state.todos;
todos= todos.filter((todo) => todo !== item);
this.setState((prevState) => ({
todos: todos
}));
};
render() {
return (<div>
<h1>The todo list:</h1>
<ul>
<TodoItem todos={this.state.todos} handleDelete={this.handleDelete}/>
</ul>
</div>);
}
}
ReactDom.render(<TodoComponent/>, document.querySelector(".todo-wrapper"));
Todo Item
import React from 'react';
import ReactDom from 'react-dom';
export default class TodoItem extends React.Component {
render() {
return (
this.props.todos.map((item) => {
return (
<li>
<div className="todo-item">
<span className="item-name">{item}</span>
<span className="item-remove" onClick={() => this.props.handleDelete(item)}> x </span>
</div>
</li>
)
}))
}
}
Your code is having the problem in TodoItem that you are trying to delete items in TodoItem where you do not have access to state. And moreover If you do some actions in component and you want to get the change reflected the your components must re render. And this is possible when your state is changed. And component related to corresponding changes will re render itself
I have not tested it so there might be some typos but you have to do it like this
import React from 'react';
import ReactDom from 'react-dom';
export default class TodoItem extends React.Component {
handleDelete(item){
this.props.updateTodos(item)
};
render() {
//Add all this.props items
let todos = this.props.todos;
todos = todos.map((item, index) => {
return (
<li>
<div className="todo-item">
<span className="item-name">{item}</span>
<span className="item-remove" onClick={this.handleDelete.bind(this, item)}> x </span>
</div>
</li>);
});
return (<React.Fragment>{todos}</React.Fragment>)
};
}
import React from 'react';
import ReactDom from 'react-dom';
import TodoItem from './todoItem';
class TodoComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
todos: ["clean up", "walk doggo", "take nap"]
};
this.updateTodos =this.updateTodos.bind(this);
}
updateTodos(item){
this.setState({todos :this.state.todos.filter((val,index) => {
return item !== val;
})})
}
render() {
return (<div>
<h1>The todo list:</h1>
<ul>
<TodoItem todos={this.state.todos} updateTodos ={this.updateTodos}/>
</ul>
</div>);
}
}
ReactDom.render(<TodoComponent/>, document.querySelector(".todo-wrapper"));