I am making an app that changes screen layout on an event detection, i.e. When the mobile detects a BLE signal, it should load the interface according to the id received. What should be the best way to do it? (setState for a variable)
DeviceEventEmitter.addListener(someevent, () => {
this.setState({some variable})
});
.....
render() {
if (this.state.some variable) {
return();
}else {
return (
regular interface
);
}
}
this is how I do it currently, I cannot navigate to different page, as this page contains listeners for two events, exit and entry. Also if i use react native router flux with API calls and loading huge data, would it affect speed?
Related
To give a bit of context, I am conducting a research focused on digital marketing and user experience. To enable the research, it is essential that I am able to get event logs from every component in an UI so I am, then, able to create datasets of usability pattern.
To do so in a web interface, e.g. using JavaScript, that's very simple.
window.addEventListener("someEvent", (e) => {//do something with the data});
The e element gives me everything I need, and If I want to listen to all window events, I can run a for loop through the window object events and add an event listener to each. My issue is with mobile development. For cross application reasons, am I am using React Native to try to create the same effect as window.addEventListener to mobile apps.
This is my first time using React Native. After a bit of searching, I am now aware that React Native does not have a window object (at least not as we understand window in JavaScript) and that the interface is translated to the platform native components, so document.getElementBy... would't work either.
What I though of was refs. I would only need to add a reference to the top component App. So what I have working so far:
export default function App() {
const viewRef = useRef();
useEffect(() => {
//I can use ref here to iterate through all events of View and
//bind event listeners to it
}, [viewRef]);
return (
<View
ref={viewRef}
style={styles.container}
onTouchEnd={(e) => {
console.log(e.target);
}}
>
<DummyComponent />
</View>
);
}
onTouchEnd event is bind to the top-layer component, so I can get everything that is a child of it. In that useEffect, I can do the same thing I would with JavaScript's window.
So I guess this is one way to do it. However, in my research I would like to enable any React Native app to begin logging events seamlessly. The state of the art would be creating a dependency that would being logging everything simply by installing it. That said, how can I iterate a React Native application to find Views and bind their events, without need to add ANYTHING to the actual component?
In JavaScript it would be something like:
document.getElementsByTagName("View").map((view) => {//bind view events});
So I'm not sure if this can help, but you can change the defaultProps of a component on start of your application.
So using your code as example you could do something like this:
const listener = e => {
console.log(e);
}
View.defaultProps = {
...View.defaultProps, // maintains original default props
onTouchEnd: listener
};
Basically this way you can have a global listener for each View component
I have a sort of Dashboard in my application. In this dashboard I let the user put many widgets (each widget is a class component). Each widget renders different stuff, such as, charts, images, and text. When I display it, each widget make an axios call to retrieve data from backend. I need a way to be able to tell when all the requests have finished so I can get the HTML completely rendered (I'm going to export it using HiqPdf later).
I need each widget to be independent so I can use in other components. That's why each widget make its own axios call. Otherwise I think I could make many axios calls in a single component that is above my widgets and then I would pass all the data as props to each widget. However, no... the axios calls must stay inside each widget.
I've found many places talking about promises, but every example talks show how to do it in a single component.
The reason I'm working on it is because I have the need to export it using a library call HiqPdf. This library receives a HTML as string and exports to PDF. Therefore, I need to know when the dashboard has been completely loaded to let the application export it.
Think about an event-driven framework that persists the global state of your single page app and notify subscribers whenever there is a change in the state.
One of the famous frameworks is redux.
Another simple framework is mufa. These are some similar questions that leverages mufa:
https://stackoverflow.com/a/42124013/747579
Stop the communication between react components using mufa after a condition
For your case, it might be something like this:
const all_calls = [];
const {on, one, fire, unsub} = mufa;
axios.get('call1').then((data) => {
fire('call1_received', data);
})
axios.get('call2').then((data) => {
fire('call2_received', data);
});
one('call1_received', () => {
all_calls.push('call1_received');
if (all_calls.length === 2) {
alert('!!!! All calls have been received')
}
})
one('call2_received', () => {
all_calls.push('call2_received');
if (all_calls.length === 2) {
alert('!!!! All calls have been received')
}
})
Note, one will subscribe once only.. while on subscribe forever.
I have a simple display which is based on some async data.
My code is as such:
componentDidMount() {
asynFunctionCall(result => {
this.setState({stateVariable: result});
});
}
And I use the state variable stateVariable to decide whether or not to show a <Text> component:
render() {
return (
<View>
{this.state.stateVariable &&
<Text> Special Message </Text>
}
</View>
);
}
What I want is for asyncFunctionCall to be run whenever the app comes to the foreground so that the user can leave the app, do something (which may affect the result of that async call), and come back to the app and have the display updated appropriately.
This seems like a standard app behavior, and I wonder if React Native's lifecycle API has a standard way to support it, but I'm not finding it.
How can I achieve this behavior, with a lifecycle function or otherwise?
Yes. you can use the AppState https://facebook.github.io/react-native/docs/appstate.html API.
I would suggest to add this somewhere at the start of the app and coordinate your views accordingly.
AppState should work mostly for iOS, but for Android background activity is triggered anytime a native module outside of your own code is triggered, e.g capturing a photo. It is way better to detect home or recent app button clicks. This is because fragments within your app from other apps like social media or photos will also trigger background state, which you don't want because they are still in the app adding a photo to a profile from the camera etc. You can easily detect home and recent app button clicks on Android with react-native-home-pressed. This library simply exposes the android button events.
First install the library with npm i react-native-home-pressed --save and then link it react-native link. Then rebuild your app and add the following snippet.
import { DeviceEventEmitter } from 'react-native'
class ExampleComponent extends Component {
componentDidMount() {
this.onHomeButtonPressSub = DeviceEventEmitter.addListener(
'ON_HOME_BUTTON_PRESSED',
() => {
console.log('You tapped the home button!')
})
this.onRecentButtonPressSub = DeviceEventEmitter.addListener(
'ON_RECENT_APP_BUTTON_PRESSED',
() => {
console.log('You tapped the recent app button!')
})
}
componentWillUnmount(): void {
if (this.onRecentButtonPressSub) this.onRecentButtonPressSub.remove()
if (this.onHomeButtonPressSub) this.onHomeButtonPressSub.remove()
}
}
I'm building a Tour component in React whose purpose is to introduce the user to the web app's interface. Parts of the "Tour" involve validating the user's actions, (e.g. if the current step involves opening a modal, once the user does so, the "Tour" should progress otherwise it should show an error if the user tries to progress by clicking 'Next').
For this I need to detect changes in the DOM, (e.g. a modal being opened or a div with a specific class appearing). I've had some ideas about wiring up an 'onNext' function that progresses the tutorial once the user interacts with certain target elements (e.g. 'Open Modal' button), but this seems like a hack, I want to govern the progression of the tour only by the actual elements present in the DOM not by listening for clicks that will result in the necessary elements showing up eventually.
One of the big constraints is avoiding MutationObservers in addition to usage of jQuery. With that said, I'm interested in hunches about how to validate the dom, how would one use pure javascript and the dom to determine the addition and removal of elements?
I think you're best served by implementing a Flux architecture to handle this. Redux is a good fit.
Create a Redux Reducer for your tour progression. The state of this reducer should be a key that corresponds to the current step of the tour that the user is within.
All components used in the tour should have access to this tour state as a prop. Use this prop to determine functionality. I.e. for your example of a dialog that must be opened, the code might look like this, within a relevant component;
openModal(){
if(this.props.tourStep == 'prompt_modal_open'){
ActionCreator.progressTourStep();
}
// code for actually opening the modal goes here
},
someOtherAction(){
if(this.props.tourStep == 'prompt_modal_open'){
//Display error message here
} else {
//normal action result here
}
}
When the user is not taking the tour, simply set tourStep in the reducer to undefined, and any tour related functionality will be turned off.
Alternately, if you want to keep your components clean and "dumb", you can put this logic directly into the action creator with the help of Redux-Thunk;
ActionCreator.openModal = function(){
return function(dispatch, getState){
var state = getState();
if(state.tourStep == 'prompt_modal_open'){
dispatch({type: 'progress_tour_step'});
}
dispatch({type: 'open_modal'});
}
}
ActionCreator.someOtherAction = function(){
return function(dispatch, getState){
var state = getState();
if(state.tourStep != undefined){
dispatch({type: 'show_error'});
} else {
dispatch({type: 'some_other_action_type'});
}
}
}
I have been writing components in React.js recently. I have never had to use methods like componentWillMount and componentDidMount.
render is indispensable. getInitialState and other helper methods I wrote also come in handy. But not the two aforementioned lifecycle methods.
My current guess is that they are used for debugging? I can console.log out inside them:
componentWillMount: function() {
console.log('component currently mounting');
},
componentDidMount: function() {
console.log('component has mounted');
}
Are there any other uses?
componentDidMount is useful if you want to use some non-React JavaScript plugins. For example, there is a lack of a good date picker in React. Pickaday is beautiful and it just plain works out of the box. So my DateRangeInput component is now using Pickaday for the start and end date input and I hooked it up like so:
componentDidMount: function() {
new Pikaday({
field: React.findDOMNode(this.refs.start),
format: 'MM/DD/YYYY',
onSelect: this.onChangeStart
});
new Pikaday({
field: React.findDOMNode(this.refs.end),
format: 'MM/DD/YYYY',
onSelect: this.onChangeEnd
});
},
The DOM needs to be rendered for Pikaday to hook up to it and the componentDidMount hook lets you hook into that exact event.
componentWillMount is useful when you want to do something programatically right before the component mounts. An example in one codebase I'm working on is a mixin that has a bunch of code that would otherwise be duplicated in a number of different menu components. componentWillMount is used to set the state of one specific shared attribute. Another way componentWillMount could be used is to set a behaviour of the component branching by prop(s):
componentWillMount() {
let mode;
if (this.props.age > 70) {
mode = 'old';
} else if (this.props.age < 18) {
mode = 'young';
} else {
mode = 'middle';
}
this.setState({ mode });
}
componentDidMount only runs once and on the client side. This is important, especially if you're writing an isomorphic app (runs on both the client and server). You can use componentDidMount to perform tasks require you to have access to window or the DOM.
From Facebook's React Page
If you want to integrate with other JavaScript frameworks, set timers using setTimeout or setInterval, or send AJAX requests, perform those operations in this method.
componentWillMount has fewer use cases (I don't really use it), but it differs in that it runs both on the client and server side. You probably don't want to put event listeners or DOM manipulations here, since it will try to run on the server for no reason.
This is an example of an isomorphic web application that makes use of componentWillMount: https://github.com/coodoo/react-redux-isomorphic-example
However, I'm 99% certain that it runs the code inside componentWillMount for no reason on the server side (I think using componentDidMount to ensure it was only run client side would have made more sense) as the code which ensures that fetch promises are fulfilled before rendering the page is in server.js not inside the individual components.
There is discussion on per-component async fetching here: https://github.com/facebook/react/issues/1739 As far as I can tell, there is not a good use case for componentWillMount as far as isomorphism is concerned at least.
In my project which is a dashboarding tool, I have used componentDidMount().
On home page previously saved dashboards appear on the sidebar. I make an ajax call within componentDidMount() of component rendering Homepage, so as to fetch list of dashboards asynchronously after the page has been rendered.
Why React Life Cycle Methods?
Intend to use third-party (Ex D3.js) library with React Component
class Example extends React.component{
constructor(){
// init state
// will be called only once
}
componentWillMount(){
// will be called only once
// will not be triggered when re-rendering
// usually will fetch data that is needed in order
// to render properly from other API
}
shouldComponentUpdate(){
return false
// will not re-render itself after componentDidMount(){}
}
render(){
return (
<div id="chart"></div>
)
}
componentDidMount(){
d3.select(".chart")
.selectAll("p")
// d3.js ........
// d3.js ........
// Usually, this will trigger React to re-render itself,
// but this time will not because we have set
// shouldComponentUpdate to false
}
}
Why React wants to do this?
Since rendering DOM is an expensive operation, React uses the layer of virtual DOM to update only DOM / DOMs that is/are different from previous state.