I set up a NativeEventEmitter and added a listener to it in my React Native app outside of any Component in index.ios.js. The listener's callback method modifies the app's global dict of localized strings which are used throughout the app's UI. I've used the ReactNativeLocalization library to display localized strings.
I need the callback to somehow refresh the UI to display the new strings, regardless of which components are currently on screen.
Here is the code for my listener:
global.localizedStrings = new LocalizedStrings({});
const myModuleEvt = new NativeEventEmitter(NativeModules.StringsEmitter);
myModuleEvt.addListener( 'LocalizedStringsUpdated', (newStrings) => {
localizedStrings = new LocalizedStrings(newStrings);
// TODO force update current screen
});
Any ideas how that could be achieved? Thanks
Related
I am using Resium and trying to utilize the useCesium() context as a dependency to a useEffect to do something when an entity is selected on the map. I have my code structured with nested components inside the Resium Viewer component.
as an example:
export function ExampleComponent() {
const {viewer} = useCesium();
useEffect(() => {
console.log(viewer?.selectedEntity);
}, [viewer?.selectedEntity]);
I've noticed when I make a dispatch through a context I've created in the app, then it seems the above useEffect will register that the selectedEntity has been updated and trigger a console.log then, but it won't update if I select a new entity on the map immediately which is my desired function.
I'm wondering if I'm not fully incorporating the useCesium() context Resium provides.
I've tried referencing many of the different objects in the useCesium context. Any object I've referenced does not seem to trigger the useEffect immediately when I interact with said objects in Viewer which is what I want to happen.
I am developing an app in React.js based on **DevExtreme** library. I need to perform some basic actions on DevExtreme widgets (NumberInput, TextInput, Button) - all of them contains method onClick or onValueChanged that should easly give me event object with whose I can do what I want.
I am able to console their values on runtime but it is almost impossible to save their values into some hook:
```
```
const handleInput = e => {
setValue(e.value); //always causes re-render
}
When I'm clicking on this button then parent component (some DevExtreme widged) performs rerender and appears imidiatetly after few seconds.
My question is - is there a way to prevent re-rendering parent component or get event object and save it to the state without re-rendering?
I'm creating a react app with useState and useContext for state management. So far this worked like a charm, but now I've come across a feature that needs something like an event:
Let's say there is a ContentPage which renders a lot of content pieces. The user can scroll through this and read the content.
And there's also a BookmarkPage. Clicking on a bookmark opens the ContentPage and scrolls to the corresponding piece of content.
This scrolling to content is a one-time action. Ideally, I would like to have an event listener in my ContentPage that consumes ScrollTo(item) events. But react pretty much prevents all use of events. DOM events can't be caught in the virtual dom and it's not possible to create custom synthetic events.
Also, the command "open up content piece XYZ" can come from many parts in the component tree (the example doesn't completely fit what I'm trying to implement). An event that just bubbles up the tree wouldn't solve the problem.
So I guess the react way is to somehow represent this event with the app state?
I have a workaround solution but it's hacky and has a problem (which is why I'm posting this question):
export interface MessageQueue{
messages: number[],
push:(num: number)=>void,
pop:()=>number
}
const defaultMessageQueue{
messages:[],
push: (num:number) => {throw new Error("don't use default");},
pop: () => {throw new Error("don't use default");}
}
export const MessageQueueContext = React.createContext<MessageQueue>(defaultMessageQueue);
In the component I'm providing this with:
const [messages, setmessages] = useState<number[]>([]);
//...
<MessageQueueContext.Provider value={{
messages: messages,
push:(num:number)=>{
setmessages([...messages, num]);
},
pop:()=>{
if(messages.length==0)return;
const message = messages[-1];
setmessages([...messages.slice(0, -1)]);
return message;
}
}}>
Now any component that needs to send or receive messages can use the Context.
Pushing a message works as expected. The Context changes and all components that use it re-render.
But popping a message also changes the context and also causes a re-render. This second re-render is wasted since there is no reason to do it.
Is there a clean way to implement actions/messages/events in a codebase that does state management with useState and useContext?
Since you're using routing in Ionic's router (React-Router), and you navigate between two pages, you can use the URL to pass params to the page:
Define the route to have an optional path param. Something like content-page/:section?
In the ContentPage, get the param (section) using React Router's useParams. Create a useEffect with section as the only changing dependency only. On first render (or if section changes) the scroll code would be called.
const { section } = useParams();
useEffect(() => {
// the code to jump to the section
}, [section]);
I am not sure why can't you use document.dispatchEvent(new CustomEvent()) with an associated eventListener.
Also if it's a matter of scrolling you can scrollIntoView using refs
I am currently developing a package, which gives my React-widget responsiveness. The problem is, that the responsiveness does not depends on the viewport-width but on on the width of the widget-container-element.
Currently I am wrapping my <App> with a <ResponsiveProvider>. This provider subscribes to the windows.resize event and stores the format into the context's value.
All children elements get re-rendered if the format changes. That's fine.
Now, for show/hide components based on the current widget format, I just could implement a component, which accesses this context with contextType.
But I need a function, which I can use in any place of my application like: ResponsiveUtil.isSmall() or ResponsiveUtil.getCurrentFormat().
What would be the best approach to make the information (format) accessable via a function?
Thanks
I'm not sure if this would be the best approach, but it will work. You can set up a global event listener that will be dispatched each time the format changes in your component. I found a package here for the global events, but it wouldn't be hard to write your own either. Using react-native-event-listeners, it would look something like:
ResponsiveUtil.js
import { EventRegister } from 'react-native-event-listeners';
let format = {};
EventRegister.addEventListener('responsive-format-changed', data => {
format = data;
});
const ResponsiveUtils = {
getCurrentFormat() {
return Object.assign({}, format);
},
isSmall() {
//isSmall logic
}
};
export default ResponsiveUtils;
Then, in your <ResponsiveProvider>, during the resize event, dispatch the new format when you update the context
ResponsiveProvider.js
import { EventRegister } from 'react-native-event-listeners';
//...Other component code
window.resize = () => {
let format = calculateNewFormat();
//update context...
//dispatch new format
EventRegister.emit('responsive-format-changed', format);
};
I'm new to ReDux, and working on a project with multiple reducers.
In the function called/referenced by the subscribe, it is called anytime any of the data in the store is changed. For example, I have a to do list and an object which stores info on the animation, basically a list of properties. If I update a to do item I don't want to re-render the animation object. If I update an animation property, I don't want to re-render the to do list.
How can I tell which data object has been changed?
Here's the code I have that subscribes to data changes in ReDux:
$(function() {
var $todoPane = $('#todopane');
var $animFormPane = $('#animation_form');
// Render objects onload.
// renderTodos($todoPane, APP.store.getState().todos.allTodos);
// renderAniPropForm($animFormPane, APP.store.getState().animation);
APP.store.subscribe(function() {
// Did some part of the ui change? (sliders that alter the height or width of panes on the page)
// Did todos change?
renderTodos($todoPane, APP.store.getState().todos.allTodos);
// Did animation values change?
renderAniPropForm($animFormPane, APP.store.getState().animation);
// Did an object change?
// Did an action change?
});
});
What do I put where the comments like with // Did ?? values change?
The standard approach used for detecting changes in React and Redux apps is strict equality checks. If two variables are not === equal, then they are assumed to be different. This requires that you update your data immutably.
So, as a quick example:
let lastTodosState, lastAnimationState;
APP.store.subscribe(function() {
// Did some part of the ui change? (sliders that alter the height or width of panes on the page)
const newState = store.getState();
if(newState.todos.allTodos !== lastTodosState.allTodos) {
renderTodos($todoPane, newState.todos.allTodos);
}
if(newState.animation !== lastAnimationState) {
renderAniPropForm($animFormPane, newState.animation);
}
lastTodosState = newState.todos;
lastAnimationState = newState.animation;
// Did an object change?
// Did an action change?
});
If you are using React for your UI layer, the React-Redux connect function generates components that do this for you automatically.
in Redux reducing operation will update the single and only state tree available which will force an entire render of all the components under a <Provider> enter reselect https://github.com/reactjs/reselect top the rescue. by suing memoized selectors you can remember properties and prevent your component from re render as long as the watched state by the selectors does not change