How do I pass the data from one React.js file to another? - html

I'd like to pass data from App.js to another .js file within React. Atm, I'm reading and writing from local storage between files but this seems inefficient. I'd like to only pull from local storage once when the App.js component mounts. This is what I'm doing currently.
App.js:
constructor(props) {
super(props);
this.state = {
user: {},
user_data: (localStorage.getItem('user_data')),
}
this.authListener = this.authListener.bind(this);
}
componentDidMount() {
this.authListener();
}
//checks firebase for authentication
authListener() {
Authentication.auth().onAuthStateChanged((user) => {
console.log(user);
if (user) {
this.setState({ user });
localStorage.setItem('user', user.uid);
this.pulldata_Health();
this.pulldata_Meals();
this.pulldata_Ingredients();
} else {
this.setState({ user: null })
localStorage.removeItem('user');
localStorage.removeItem('user_data')
}
});
}
//connects to database and stores data to local storage
pulldata_Health() {
database.collection('Health_data')
.doc(localStorage.getItem('user'))
.get()
.then(doc => {
const data = doc.data();
localStorage.setItem('user_data', JSON.stringify(data));
console.log(JSON.parse(localStorage.getItem('user_data')))
}).catch(function (error) {
console.error("Error reading health", error);
});
Homepage.js:
constructor(props) {
super(props);
this.state = {
healthData: (JSON.parse(localStorage.getItem('user_data')))
}
}
componentDidMount() {
this.GoalChecker();
console.log(this.state.healthData);
}
GoalChecker() {
if (this.state.healthData !== null) {
if (this.state.healthData.goal === 'Gain') {
this.setState({ gainImage: true });
this.setState({ recompImage: false });
this.setState({ loseImage: false });
console.log('gainimg')
}
if (this.state.healthData.goal === 'Recomp') {
this.setState({ gainImage: false });
this.setState({ recompImage: true });
this.setState({ loseImage: false });
console.log('recompimg')
}
if (this.state.healthData.goal === 'Lose') {
this.setState({ gainImage: false });
this.setState({ recompImage: false });
this.setState({ loseImage: true });
console.log('loseimg')
}
}
};
This all works, but pulling from local storage every time this page loads seems a bit inefficient. Is there any way to push the props of User data from App.js to my other page?

It is very difficult for me to explain, but i'll show you a video from YouTube how to do this with react-hooks. It is not a very difficult method
https://youtu.be/XuFDcZABiDQ

YOu can use react context. Create a context within app.js/at the top of your application. Wrap the top-level container using a context component. Within any child components, you can then access props in the global context.
A great tutorial that explains it is here, https://kentcdodds.com/blog/how-to-use-react-context-effectively

Related

Waiting Before Writing to Database

I have a giant form, and it's setup so that the handleChange method changes the state values of the data as the user types. I then want it to write to the mySql database, which I can also do, except currently, it writes after every keypress. I'm trying to figure out how to wait a few seconds after input stops, so that it doesn't do it after every single key press.
handleChange(e) {
const targetName = e.target.name;
const targetValue = e.target.value
this.setState({
[e.target.name]: e.target.value
});
console.log(`${targetName}: ${targetValue}`);
/// I want a timer here that will only move on if input has stopped for a few seconds.
/// Call to my database query will be here
}
For anyone who wants the answer that I used, I put it together from the link that #WilTree posted above.
let timeout;
class General extends Component {
constructor(props) {
super(props);
this.state = {
typing: false,
typingTimeout: 0,
organization: "",
address: "",
website: "",
industry: "",
status: ""
};
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
const targetName = e.target.name;
const targetValue = e.target.value
this.setState({
[e.target.name]: e.target.value
});
if (this.state.typingTimeout) {
clearTimeout(this.state.typingTimeout);
}
this.setState({
typing: false,
typingTimeout: setTimeout(function () {
console.log(`${targetName}: ${targetValue}`);
}, 3000)
});
}

Vue.js - Store data into session

How do I store my dadta in a session so I can access it in any page? And only destroy the data whenever the page is closed.
Vue.js:
new Vue({
el: '#item-data',
data () {
return {
data:[],
selectedUser:'',
itemCart: [],
quantity: ''
}
},
mounted () {
**** API CALL ****
}
})
.then((response) => {
// handle success
this.data = response.data.items
removeLoader();
})
.catch(function (error) {
// handle error
console.log(error);
})
.then(function () {
// always executed
});
},
methods:{
sendInfo(items) {
this.selectedUser = items;
},
addCart: function(cartdets){
this.itemCart.push({cartdets});
console.log(cartdets);
}
}
})
The data i want to store into a session is itemCart[].

How do I make my table dynamically change based on year?

I'm trying to populate a table with some information pulled from my database through an API based on year. I'm using React Router and would like to keep my sidebar with the links to different years, but dynamically change the table that is the main focus of this page.
I can get the Table to render with the first year(2019, since this is the default link), but that's only if it's outside the <Switch>. This also causes the problem that it doesn't change when the link changes.
class YearlyTable extends React.Component {
state = {
yearlyTable: [],
isLoading: false,
}
componentDidMount() {
this.setState({ isLoading: true });
axios.get(
`http://localhost/yearTable/${this.props.match.params.yearId}${this.props.location.search}`,
{ withCredentials: true }
).then(res => {
const yearlyTable = res.data;
this.setState({ yearlyTable, isLoading: false });
}).catch((error) => {
console.log(error);
});
}
render() {
// isLoading component
// Check what API returns
console.log(this.state.yearlyBonds);
return (
// Removed for simplicity
// This returns a table
{this.state.yearlyTable && <ListTable title={this.state.yearlyTable.Title} data={this.state.yearlyTable.Bonds} />}
// This does not
<Switch>
<Route exact path={`/yearly_table/${this.props.match.params.yearId}${this.props.location.search}`} render={() => this.state.yearlyTable && <ListTable title={this.state.yearlyTable.Title} data={this.state.yearlyTable} />} />
</Switch>
// Sidebar removed for simplicity
);
}
}
export default withRouter(YearlyTable);
The outcome I'm wanting to achieve is that it renders the first table, but when you press one of the links, then it changes out the table with the new contents.
This is happening because you are using componentDidMount. This is called only for the first render, not after that.
You can do something like
class YearlyTable extends React.Component {
state = {
yearlyTable: [],
isLoading: false,
}
componentDidMount() {
this.setState({ isLoading: true });
axios.get(
`http://localhost/yearTable/${this.props.match.params.yearId}${this.props.location.search}`,
{ withCredentials: true }
).then(res => {
const yearlyTable = res.data;
this.setState({ yearlyTable, isLoading: false });
}).catch((error) => {
console.log(error);
});
}
updateData(){
axios.get(
`http://localhost/yearTable/newYearID${this.props.location.search}`,
{ withCredentials: true }
).then(res => {
const yearlyTable = res.data;
this.setState({ yearlyTable, isLoading: false });
}).catch((error) => {
console.log(error);
});
}
render() {
// isLoading component
// Check what API returns
console.log(this.state.yearlyBonds);
return (
// Removed for simplicity
// This returns a table
{this.state.yearlyTable && <ListTable title={this.state.yearlyTable.Title} data={this.state.yearlyTable.Bonds} />}
<Link onClick={this.updateData.bind(this, clickedItemYear)}>Some Item</Link>
);
}
}
export default withRouter(YearlyTable);
You can use and preventDefault or stopPropogation of the event. Better make a function call , so that it is called again whenever there is some user action.

user photo in tab navigation

In a react native project I am trying to set the user's profile photo as a tabBarIcon in tabNavigation. Below is how I am trying to retrieve the photo path and set it in the source for TabBarIcon.
First I have a token in AsyncStorage that gives me the username, email, or phonenumber of the user after login (works fine). This is in my constructor:
constructor(props) {
super(props)
this.state = {
Access: []
}
}
I set the Access in my state to a value in my AsyncStorage with getItem('Access') which i know works fine.
Now i have a function getProfilePhoto where I use fetch to get the profile photo.
getProfilePhoto = () => {
const { Access } = this.state.access;
fetch('http://urltofiletogetprofilephoto', {
method: 'POST',
headers: {
'Accept':'application/json',
'Content-Type':'application/json',
},
body: JSON.stringify({
Access:Access
})
}).then((response) => response.json())
.then((responseJson) => {
if(responseJson === 'NULL') {
console.log('../Images/NoPhoto.png');
} else {
console.log('../' + responseJson);
}
})
}
What I return from that file is:
$profilephoto = $row['ProfilePhoto'];
$profilephotoJson = json_encode($profilephoto);
echo $profilephotoJson;
That should return something like "Images/userprofilephoto.png". Now in navigationOptions I have this:
static navigationOptions = {
tabBarLabel: 'Profile',
tabBarIcon: ({ tintColor }) => (
<Image
source = {this.getProfilePhoto}
style={[styles.icon, {tintColor: tintColor}]}
/>
)
}
I thought calling the function would print the returned Image path, but when I run the app on my device I don't get an error but my tabBarIcon Image is just blank. I am new to react native and haven't worked with Json much I am hoping someone will be able to see something wrong that I am missing!
try
source={require(this.getProfilePhoto())}
However your function getProfilePhoto is not returning a path as you are using fetch.
Also navigationOptions is static, so this is not available.
You will need to access it via navigation params
static navigationOptions = ({ navigation }) => {
const { state } = navigation;
return {
tabBarLabel: 'Profile',
tabBarIcon: ({ tintColor }) => (
<Image
source = {state.params.getImage()}
style={[styles.icon, {tintColor: tintColor}]}
/>
)
}
}
componentWillMount() {
this.props.navigation.setParams({
getImage: () => {
this.getProfilePhoto();
},
});
}
getProfilePhoto () => {
//here you can get the path from this.props which would be added
//as before the component mounts
return this.props.profileImagePath; //set from redux connect
}
One downside with this is that if you want to update the image on the fly, you will need to call setParams again to force it to re-render the tab.
componentWillReceiveProps(nextProps) {
this.props.navigation.setParams({
getImage: () => {
this.getProfilePhoto();
},
});
}
I would have the action of getting the image separate to the component, and use Redux to connect to the latest image path. You can therefore set the Redux store triggered from another component.
You probably need to setState when your promise resolved by adding the data fetching request in the comoponentWillMount hook and make sure your image resides in the generated location relative to your component.
class UserProfile extends React.Component {
constructor(props) {
super(props)
this.state = {
Access: []
image: null
}
}
componentWillMount() {
this.getProfilePhoto();
}
getProfilePhoto = () => {
const { Access } = this.state.access;
fetch('http://urltofiletogetprofilephoto', {
method: 'POST',
headers: {
'Accept':'application/json',
'Content-Type':'application/json',
},
body: JSON.stringify({
Access:Access
})
}).then((response) => response.json())
.then((responseJson) => {
if(responseJson === 'NULL') {
console.log("../Images/NoPhoto.png");
} else {
this.setState({image: responseJson})
}
})
}
render() {
return (
this.state.image
?
<Image
source={require(this.state.image)}
style={this.props.style}
/>
:
null
)
}
}
static navigationOptions = {
tabBarLabel: 'Profile',
tabBarIcon: ({ tintColor }) => (
<UserProfile
style={[styles.icon, {tintColor: tintColor}]}
/>
)
}

accessing object attributes in the react render method

I have written a small react component which fetches some data from the open weather api. The fetch succeeds and I can get a json object in the response.
I then save this response to the components state using this.setState({})
And the react dev tools show the forecast object is infact saved in state.
However when I come to rendering any of the data i always get an error stating `cannot read property 'forecast' of null.
Below is the react component and a screen shot of the object itself.
export default class Weather extends Component {
getWeather () {
var self = this;
fetch('http://api.openweathermap.org/data/2.5/weather?zip=sl44jn,uk&units=metric&APPID=ed066f80b6580c11d8d0b2fb71691a2c')
.then (function (response) {
if (response.status !== 200) {
console.log('Looks like there was a problem. Status Code: ' + response.status);
return;
}
response.json().then(function(data) {
self.setWeather(data);
});
})
.catch (function (err) {
console.log('Fetch Error :-S', err);
});
}
setWeather (forecast) {
console.log(forecast);
this.setState({
forecast: forecast.name
})
}
componentWillMount () {
this.getWeather();
}
componentDidMount () {
// window.setInterval(function () {
// this.getWeather();
// }.bind(this), 1000);
}
render() {
return (
<h1>{this.state.forecast}</h1>
)
}
}
And this is the data object itself, right now I am simply trying to access the name attribute.
Looks like you forgot couple of things, in order to a Component to setState you need to bind it to this preferably in the constructor. You also need to set the initial state, in your case an empty object, and you can save the whole response in the object and access just the parts you want. have a look:
export default class Weather extends Component {
constructor() {
super();
this.state = {
forecast: {}
};
this.setWeather = this.setWeather.bind(this);
}
getWeather () {
let self = this;
fetch('http://api.openweathermap.org/data/2.5/weather?zip=sl44jn,uk&units=metric&APPID=ed066f80b6580c11d8d0b2fb71691a2c')
.then (function (response) {
if (response.status !== 200) {
console.log('Looks like there was a problem. Status Code: ' + response.status);
return;
}
response.json().then(function(data) {
self.setWeather(data);
});
})
.catch (function (err) {
console.log('Fetch Error :-S', err);
});
}
setWeather (forecast) {
this.setState({
forecast: forecast
});
}
componentWillMount() {
this.getWeather();
}
render() {
const { forecast } = this.state;
return (
<h1>{forecast.name}</h1>
)
}
}