Problem
I want to have a global counter in react native to show how many notifications a user has in an app that I am creating.
I created a global variabal in a file named global.js:
var notifNum = 0;
global.n = notifNum;
then in my code, I import it with
import './global.js'
then later I try to update it with
global.n = notifNum;
Notif num being the number of notifications a user has, defined in a function. The problem is that global.n stays as 0, and doesn't change at all.
How can I edit the global.n variable?
There is one hacky way to modify a global.foo variable.
Dosnt work
global.foo = 'foo'; //this cant be changed
global.foo = 'foofoo';
console.log(global.foo); //foo
Does work
global.foo = ['foo']; //this can be changed
global.foo[0] = 'foofoo';
console.log(global.foo[0]); //foofoo
This has less to do with React-Native and more to do with how javascript works as a language.
In short, you must export what you wish to use in other files.
Global.js
let counter = 0;
const increment = () => {
counter++;
console.log('counter_updated', counter);
};
const worker = {
increment,
counter
};
module.exports = worker;
We've told the JS engine exactly what we want to import in other files. Assigning it to and object and exporting the object is not necessary but allows for cleaner imports/exports IMO.
Component.js
import { counter, increment } from 'pathTo/global';
We deconstruct the object we exported and are now able to modify/use values in the global.js file.
Food for thought
This is not an ideal solution as it is not two ways. Incrementing the count in the global.js file will not update the value in the component.js.
This is because React needs to have it's state updated to initiate a re-render of a component.
Also, this will not persist through app reloads, which I believe you would want for something such as notifications.
Other solutions
Storing the notification counts in a database.
Using component state to manage the count.
Using a state manager like Redux or MobX
Related
I've written a file which contains a Table that should display codes when there are pushed inside the array codes with prop name code (e.x. "848389494")
now every time the function addNewCode is called it should update the _codeData Object but it's not possible because its an outer scouped function. i cant move it inside ScannerResultTable because addNewCode should be able to be exported and used in another Component.
but i dont know how its not possible to useEffect and keep track on "codes" but it wont allow it because it's an outerscouped var.
thanks for your help-
const codes = []
export function addNewCode(value){
codes.push({ code: value });
}
export default function ScannerResultTable() {
const [_codeData, setCodeData] = useState([]);
useEffect(() => {
console.log("Hi im rendering");
setCodeData(codes);
}, []);
const [tableData, setTableData] = useState(_codeData);
Instead of using a globally defined variable codes, you can make use of React context and make the codes a state in some parent components and pass down the utility function to update the codes to the child components that are gonna update it.
More details on how to use react context can be found here
I'm using react-admin. I have firebase.js, which exports a data provider and an auth provider. Right now firebase.js looks something like
export const authProvider = MyCustomAuthProvider(...)
export const dataProvider = FirebaseDataProvider(..., {rootRef: "users/[authProvider.get~this~user().email]")
But I'd like the dataProvider imported to change when the user logs in / out (the reason being that the data provider has as its root collection at 'users/[user email]'). That's actually why I stopped using the FirebaseAuthProvider blackbox, because I figured I could use the login/logout functions to trigger changing the dataProvider.
What's the best way to accomplish this? Just declare the dataProvider using
let dataProvider = null and every time a user logs in/out, set that variable. And then add a function to the auth provider that returns that variable? There seems to be a more elegant way, but I'm not as experienced in JavaScript unfortunately.
Also for reference, the reason I'm taking this approach instead of just creating a dataProvider with rootRef 'users' and then accessing the correct collection / document when I want to view or modify data is because FirebaseDataProvider is a bit of black box and doesn't allow me to do that (unless I'm missing something). If I could get this all to work with FirebaseDataProvider, it has saved me a ton of time so that would be great.
I have two different files currently (file1.jsx and file2.jsx both in the same directory). file2.jsx depends on the list of file1.jsx, so I want to be able to call the list somehow. This is my current implementation.
file1.jsx:
function file1 {
// this is the list I want to call in file2.jsx
const [currentSelection, setCurrentSelection] = uuseState([]);
// also tried export const [currentSelection, setCurrentSelection] = uuseState([]);
...
}
file2.jsx:
//gave me errors
import { currentSelection } from "file1";
function file2 {
...
}
If I can get some help, I would much appreciate it!
State in react-native is internal data-set which affects the rendering of components .It is private and fully controlled by the component .
However if you want to use value of currentSelection in file2 , you can store the value of currentSelection in some central store like redux and then fetch it in file2.
Firstly, you wrote uuseState which should be useState, second for you solution. There are many ways to store an array (assuming that you what to pass to second screen by initial value of your use state is empty array)
You can pass it by react Navigation's params if you are using it,
You can store it using async storage and call that storage on second screen.
I want to create a helper that generates some data and saves it in some variable and on the next execution, it should use the memoized value for calculation.
Basically it's a helper for the High Order wrapper. It means that the storage should be created for every HOC but it shouldn't be re-created on the next re-render.
Now it looks like:
pseudo code
var storage; // I want to create this storage for every HOC only once.
function createDynamicStyles(theme, stylesCreator, status) {
// create a styles registry only once. This function can be re-called by the same HOC
// on each re-render so I want to use the memoized registry.
if (!storage) {
storage = stylesCreator(theme);
};
return storage[status];
}
const styleCreator = theme => ({
disabled: { color: theme.disabled },
success: { color: theme.success }
})
const Component_1 = componentHOC((props) => {
const { theme, status } = props;
// I'd like to keep this helper call as simple as possible. It already has 3 arguments.
const finalStyle = createDynamicStyles(theme, stylesCreator, status);
})(AwesomeComponent)
// these props can be changed during runtime
<Component_1 disabled={false} success={true} />
The functionality flow of this helper can be divided into 2 steps.
1) The first HOC call. It creates the styles based on the theme and saves them in the storage
2) Next Re-render of the HOC. It should fetch the previously created styles and return memoized value. This value should be unique for each HOC.
The problem is that the same helper can be used for other Components as well and it means that we can't use the same storage because it will be overwritten but the 'latest' HOC.
The possible ways how to solve it:
1) Create a class that will contain storage itself and creates a new Instance for each HOC.
To be honest, I'd like to avoid it because it looks too complicated for me in this case.
2) Create some Shared Registry and pass the UUID for every HOC.
It'd be nice but I don't know how to automatically do it. I don't want to manually pass the UUID on each HOC. I'd like to have this functionality under the hood to keep HOC calls, lightweight.
I was thinking about the new Map, and saving the created styles as Key-Value pair but it simply doesn't work as we don't have the generated KEY reference in the HOC. So we can't use it as a key.
Is it possible to do such a thing in the case of plain functions only?
Maybe I missed some other interesting variants.
Thanks for any help and suggestion.
Kind Regards.
I've used higher order component to share a function between my components.With this implementation,the function comes as a prop in my component.The app supports multi languages so in each component a key is passed and the hash value is obtained to display. Hash values are passed to all the components using the context. Now getSkinHash access the context and returns the hash value.
const {getSkinHash} = this.props; //shared function,accesses the context
const value = getSkinHash(SOME_VALUE);
No problem with this implementation but getting the function out of prop every time leads to writing lot's of boilerplate code in all the components.
Is there a better/alternate ways to achieve this?
Thanks
React works with properties, so you can't just say you don't want to work with properties. That is when sharing data between components.
As far as you can do to shorten
const {getSkinHash} = this.props;
const value = getSkinHash(SOME_VALUE);
is to:
this.props.getSkinHash(SOME_VALUE).
If that is a generic function, not component dependent, you can choose to import it into your component just like you import other stuff.
import { myFunction } from './functions'
Then you would simple call it with myFunction.
If you need your function to synchronize data between your components, use a Redux action and connect your components to the global state. Your other components will get to know value hash changes too.