How to pass function as props in React? - reactjs

I have functional component GetWeather which I want to pass result of GetLocation function as props based on which GetWetaher will do something i.e. another get request (in the example below it only renders its props). I think it has to happen inside ComponentDidMount, not sure how to do it
function GetLocation() {
axios.get('http://ipinfo.io')
.then((res) => {
return res.data.loc;
})
}
function GetWeather(props) {
//more code here, including another get request, based on props
return <h1>Location: {props.location}</h1>;
}
class LocalWeather extends Component {
componentDidMount() {
//???
}
render() {
return (
<div >
<GetWeather location={GetLocation}/> //???
</div>
);
}
}
Update: So based on suggestion from Damian below is working for me
function GetWeather(props) {
return <h3>Location: {props.location}</h3>;
}
class LocalWeather extends Component {
constructor(props) {
super(props);
this.state = {
location: []
};
}
getLocation() {
axios.get('http://ipinfo.io')
.then((res) => {
this.setState({location:res.data.loc});
})
}
componentDidMount() {
this.getLocation();
}
render() {
return (
<div >
<GetWeather location={this.state.location}/>
</div>
);
}
}

You can do it alternatively also
constructor() {
super();
this.state = {
Location:[]
}
}
function GetLocation() {
axios.get('http://ipinfo.io').then((res) => {
this.setState ({
Location:res.data.loc;
});
});
}
function GetWeather(props) {
return <h1>Location: {this.props.location}</h1>;
}
class LocalWeather extends Component {
componentDidMount() {
//code
}
render() {
return (
<div >
<GetWeather location={this.GetLocation.bind(this)}/>
</div>
);
}
}

Related

How to reload "url" every second using React

I want to reload URL every 5 seconds. Below is my code. What do I do wrong? Please let me know is there anything important point which I missed.
class RandomImg extends Component {
constructor(props) {
super(props);
this.state = { image: "https://picsum.photos/100" };
}
componentDidMount() {
this.imgID = setInterval(() => {
this.tickImg();
}, 1000);
}
componentWillUnmount() {
clearInterval(this.imgID);
}
tickImg() {
this.setState({ image: "https://picsum.photos/100" });
}
render() {
return (
<div>
<h4>This is Random IMG:</h4>
<img src={this.state.image}></img>
</div>
);
}
}
Your image URL is not changing and thus the component is not being updated.
Try this
class RandomImg extends Component {
constructor(props) {
super(props);
this.state = { image: "https://picsum.photos/100" };
}
componentDidMount() {
this.imgID = setInterval(() => {
this.tickImg();
}, 1000);
}
componentWillUnmount() {
clearInterval(this.imgID);
}
tickImg() {
this.setState({ image: "https://picsum.photos/100?" + Math.random() });
}
render() {
return (
<div>
<h4>This is Random IMG:</h4>
<img src={this.state.image}></img>
</div>
);
}
}
You URL is not changing on the tick so the state remains the same. Try adding some random string into the URL
for e.g.
tickImg() {
this.setState({random: this.state.random++ } , () => {
this.setState({ image: "https://picsum.photos/100?r=" + this.state.random });
})
}
class RandomImg extends Component {
constructor(props) {
super(props);
this.state = { image: "https://picsum.photos/100" };
}
componentDidMount() {
this.imgID = setInterval(() => {
this.tickImg();
}, 5000);
}
componentWillUnmount() {
clearInterval(this.imgID);
}
tickImg() {
this.setState({
image: `https://picsum.photos/${Math.floor(Math.random()*100)}`
});
}
render() {
return (
<div>
<h4>This is Random IMG:</h4>
<img src={this.state.image}></img>
</div>
);
}
}

React: fire render after promise completed

Please note, that I a fetching data from AWS DynamoDB.
...
class Test extends Component {
constructor(props) {
super(props);
this.state = {
contactList: []
}
}
componentDidMount() {
var getItemsPromise = db.scan({ TableName: "tester" }).promise();
getItemsPromise.then((data) => this.setState({ contactList: data.Items }));
}
render() {
return (
<div>{this.state.contactList[0].link.S}</div>
);
}
}
export default Test;
I am trying to render the returned value, but can't. If I set
render() {
console.log(this.state.contactList[0].link.S);
return (
<div>test</div>
);
}
it works. Why is that? Why is it not working when I set it straight inline?
this.state.contactList[0] is undefined before the promise is resolved, so this.state.contactList[0].link will give rise to an error.
You could e.g. return null from the render method until the array has been filled with your objects:
class Test extends Component {
// ...
render() {
if (this.state.contactList.length === 0) {
return null;
}
return <div>{this.state.contactList[0].link.S}</div>;
}
}

why do I have "Warning: undefined(...): Cannot update during an existing state transition..." error?

so i have this in my code like this:
class TimersDashboard extends React.Component{
constructor() {
super(props);
this.state = {
timers: [
{id: uuid.v4(), text:'I am the first id' },
{ id:uuid.v4(), text:'I am the second text' }
]
};
}
clickEdit(id) {
this.openForm(id);
}
openForm(id) {
this.setState({
timers: this.state.timers.map((timer) => {
if(timer.id === id) {
return Object.assign({}, timer, { editFormOpen: true });
} else {
return timer;
}
})
});
}
handleCloseForm(id) {
this.closeForm(id);
}
closeForm(id) {
this.setState({
timers: this.state.timers.map((timer) => {
if(timer.id === id) {
return Object.assign({}, timer, { editFormOpen: false });
} else {
return timer;
}
})
});
}
}
render() {
return (
<Timer id={this.state.data[0].id} onEdit={this.clickEdit.bind(this)} onDelete = {this.handleCloseForm.bind(this)}/> // as if wroking on the first id
);
}
}
}
However, below, I passed the methods as props, the other component I tried to invoke these the same way, you can see their code is slightly similar in way.
class Timer extends React.Component {
constructor(props) {
super(props);
this.handleEditClick = this.handleEditClick.bind(this);
this.handleTrashClic = handleTrashClic.bind(this);
}
handleEditClick() {
this.props.onDelete(this.props.id);
}
handleTrashClick() {
this.props.onEdit(this.props.id);
}
render() {
return(
// ... onClick = {()=>this.handleEditClick(this.props.id)} ..
// ... onClick = {()=>this.handleTrashClick(this.props.id)} ..
);
}
}
}
I code them same way on other component, the delete method works on other component but I don't know why the Edit method does not and I can't make it work, I tried to pass the parentObj context, added .bind(this), But I cannot make it work. My error is "Warning: undefined(...): Cannot update during an existing state transition...". How do I make it work?
Created the same example in jsfiddle, its working. Try this:
Parent Component:
class TimersDashboard extends React.Component{
constructor(props) {
super(props);
this.state = {
timers: [
{id: 1, text:'I am the first text' },
{id: 2, text:'I am the second text' }
]
};
}
edit(id){
let timers = this.state.timers.map((timer) => {
if(timer.id === id) {
return Object.assign({}, timer, { editFormOpen: true });
} else {
return timer;
}
})
this.setState({timers});
}
remove(id){
let timers = this.state.timers.map((timer) => {
if(timer.id === id) {
return Object.assign({}, timer, { editFormOpen: false });
} else {
return timer;
}
})
this.setState({timers});
}
render() {
return (
<div>
<Timer id={1} edit={this.edit.bind(this)} remove={this.remove.bind(this)}/>
</div>
);
}
}
Child Component:
class Timer extends React.Component{
constructor(props) {
super(props);
this.state={};
}
edit(id){
this.props.edit(id);
}
remove(id){
this.props.remove(id);
}
render(){
return(
<div>
In Child Component:
<br/>
Id: {this.props.id}
<p onClick={this.edit.bind(this,this.props.id)}>Edit</p>
<p onClick={this.remove.bind(this,this.props.id)}>Remove</p>
*click on edit and remove to change the state
</div>
)
}
}
Check jsfiddle for working example: https://jsfiddle.net/wqkfqusk/

ReactJS show loader on child component update

I have seen a lot loader plugins that work for the Mount life cycle but none for the update part and I wonder how to handle it?
What I tried was following setup for parent:
class App extends React.Component {
constructor() {
super()
this.state = {loader_wrap:false};
this.hideLoader = this.hideLoader.bind(this);
this.showLoader = this.showLoader.bind(this);
}
hideLoader(){
this.setState({loader_wrap: false});
}
showLoader() {
this.setState({loader_wrap: true});
}
render() {
var loaderStyle;
if (this.state.loader_wrap) {
loaderStyle = {display:"block"};
} else {
loaderStyle = {display:"none"};
}
return (
<div>
<div id="content">
{React.cloneElement(content, {
hideLoader: this.hideLoader,
showLoader: this.showLoader
})}
</div>
<div id="loader-wrap" style={loaderStyle}>
<img className="loader hidden-sm hidden-xs" src='source/file/'>
</div>
</div>
)
}
}
And this is the child calling the methods:
class Childextends React.Component {
constructor() {
super();
this.state = {results:[]};
this.calculate = this.calculate.bind(this);
}
calculate(dict) {
this.props.showLoader();
Actions.action(dict)
.then(results => {
this.setState({results: results});
})
.catch((err) => {
var errResp = JSON.parse(err.response);
console.log(errResp);
this.setState({responseErrors: errResp});
});
}
componentDidMount() {
this.props.hideLoader();
}
componentDidUpdate() {
this.props.hideLoader();
}
componentWillReceiveProps(values){
this.setState({results:values.results});
}
render() {
return (
/*stuff to be returned*/
)
}
}
I also tried to use the Will methods .. which worked even worser :D
Any ideas how to implement this? I use react with flux but don't now how to use it in this case ..
Why not just call hideLoader() in the callback of the action's promise?
class Childextends React.Component {
constructor() {
super();
this.state = {results:[]};
this.calculate = this.calculate.bind(this);
}
calculate(dict) {
this.props.showLoader();
Actions.action(dict)
.then(results => {
this.setState({results: results});
})
.catch((err) => {
var errResp = JSON.parse(err.response);
console.log(errResp);
this.setState({responseErrors: errResp});
})
.then(() => {
this.props.hideLoader();
});
}
render() {
return (
/*stuff to be returned*/
)
}
}
Edit: A different approach to the parent component as well - rather than hiding the element with a style, just don't render it if it isn't required.
render() {
return (
<div>
<div id="content">
{React.cloneElement(content, {
hideLoader: this.hideLoader,
showLoader: this.showLoader
})}
</div>
{this.state.loader_wrap &&
<div id="loader-wrap" style={loaderStyle}>
<img className="loader hidden-sm hidden-xs" src='source/file/'>
</div>
}
</div>
)
}

Is it possible to set the context after the component mounts in React?

I wish to add the checks done (once the component mounts in CDM) to detect userAgent - for the purposes of mobile/flash/touchDevice detections to context rather than to the state. Is this possible? if so how would you do that? I am currently getting undefined when I attempt to access the value fo the context for the isFlashInstalled. Here is glimpse into the component setting the context:
App.js
export class App extends Component {
static childContextTypes = {
isFlashInstalled: React.PropTypes.bool
};
constructor() {
super();
this.state = {
isFlashInstalled: false
};
}
getChildContext() {
return {
isFlashInstalled: this.state.isFlashInstalled
};
}
componentDidMount() {
const flashVersion = require('../../../client/utils/detectFlash')();
// I know this could be done cleaner, focusing on how for now.
if (flashVersion && flashVersion.major !== 0) {
this.setFlashInstalled(true);
} else {
this.setFlashInstalled(false);
}
}
setFlashInstalled(status) {
this.setState({isFlashInstalled: status});
}
}
Later when trying to access isFlashInstalled from context I will get undefined
ChildComponent.js
export class ChildComponent extends Component {
// all the good stuff before render
render() {
const {isFlashInstalled} = this.context
console.log(isFlashInstalled); // undefined
}
}
did you correctly set up context types for parent and child? I did a test and it works, see the componentDidMount that set the state asynchronously:
class Parent extends React.Component {
state = {
color: 'red'
}
getChildContext() {
return {
color: this.state.color
};
}
componentDidMount() {
setTimeout(() => this.setState({color: 'blue'}), 2000)
}
render() {
return (
<div>Test <Button>Click</Button></div>
);
}
}
Parent.childContextTypes = {
color: React.PropTypes.string
}
class Button extends React.Component {
render() {
return (
<button style={{background: this.context.color}}>
{this.props.children}
</button>
);
}
}
Button.contextTypes = {
color: React.PropTypes.string
};
http://jsbin.com/cogikibifu/1/edit?js,output

Resources