I have a react native project I am going to localize with expo-localization and I have some questions about the process, mainly If the way I'm doing this is the right approach and one concrete question I have about beign able to use user language stored in redux outside components.
First, the way I'm doing it is:
app/i18n.js
import * as Localization from 'expo-localization'
import { I18n } from 'i18n-js'
import translations from '#app/locales'
const i18n = new I18n(translations)
i18n.enableFallback = true
i18n.locale = Localization.locale
export default i18n
app/components/RandomComponent.js
import * as React from 'react'
import { Text } from 'react-native'
import i18n from '#app/i18n'
const RandomComponent = () => {
return <Text>{i18n.t('key')}</Text>
}
export default RandomComponent
app/services/RandomService.js
import i18n from '#app/i18n'
const method = () => {
return i18n.t('key')
}
export default {
method
}
So far it works just fine. Then I add user language, stored in redux store:
app/components/RandomComponent.js
import * as React from 'react'
import { Text } from 'react-native'
import i18n from '#app/i18n'
const RandomComponent = () => {
i18n.locale = /* use locale from redux store */
return <Text>{i18n.t('key')}</Text>
}
export default RandomComponent
app/services/RandomService.js
import i18n from '#app/i18n'
const method = () => {
i18n.locale = /* use locale from redux store does not work cause it is outside of components */
return i18n.t('key')
}
export default {
method
}
So that's the thing:
Is ok the way i'm organizing this?
How can I use localization with user language stored in redux outside of components? It guess it can not be done because that code is outside store provider? Should I just pass i18n as a parameter in service method calls?
Related
Problem
I am using Redux Toolkit and TypeScript to create a Todos app. I want to create middleware that will listen for a dispatched action so I can then dispatch async actions.
What I have so far
// listenerMiddleware.ts
import { createListenerMiddleware, addListener } from '#reduxjs/toolkit'
import type { TypedStartListening, TypedAddListener } from '#reduxjs/toolkit'
import type { RootState, AppDispatch } from './store'
export const listenerMiddleware = createListenerMiddleware()
export type AppStartListening = TypedStartListening<RootState, AppDispatch>
export const startAppListening =
listenerMiddleware.startListening as AppStartListening
export const addAppListener = addListener as TypedAddListener<
RootState,
AppDispatch
>
const store = configureStore({
reducer: {
todos: todosReducer,
},
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().prepend(listenerMiddleware.middleware),
})
Question
How do I use the startAppListening and addAppListener objects to listen for a specific action? I can't find any examples.
We do show extensive examples in the API reference page :)
https://redux-toolkit.js.org/api/createListenerMiddleware
Generally, it's going to look like this:
import { todoAdded } from "../features/todos/todoSlice"
startAppListening({
actionCreator: todoAdded,
effect: (action, listenerApi) => {
// whatever logic you want here
}
})
I want to change a hook name and its return values while exporting them.
Here is my use case.
I want to use notistack api to show some toasts in my application. However, because I don't like the name snackbar I want to change it to toast. Here is how I start doing it:
export { SnackbarProvider as ToastProvider, useSnackbar as useToast } from 'notistack';
But I can't manage to change the name of the variables returned from the useSnackbar hook.
const { enqueueSnackbar, closeSnackbar } = useSnackbar();
should be
const { addToast, closeToast } = useToast();
how can I achieve this?
thank you.
You can define a custom hook that wraps the useSnackbar hook as follow:
import { SnackbarProvider, useSnackbar } from 'notistack';
export const useToast = () => {
const { enqueueSnackbar, closeSnackbar } = useSnackbar();
return { addToast: enqueueSnackbar, closeToast: closeSnackbar };
};
export const SnackbarProvider = ToastProvider;
You can learn more about building custom hooks on the documentation: https://reactjs.org/docs/hooks-custom.html
In the code below I would like to know, how to export the function setFormData. In other words also I would like to know how to import setFormData from a different typescript file. Thank you
File A
import { SyntheticEvent } from 'react';
import { useDispatch } from 'react-redux';
import { useStatusActions } from '../../actions';
export const StatusHelper = () => {
const dispatch = useDispatch();
let statusActions = useStatusActions(dispatch);
const setFormData = (event: SyntheticEvent, key: any, value: any) => {
statusActions.setFormData(key, value);
};
File B
import {
setFormData,
} from './fileA';
you will need to create a custom hook if you want to export a function that relies on another hook. You can't simply export and use it outside react.
you should have a useStatusHelper hook that returns a setFormData function
check how to create custom hooks here
So technically I have 2 components, I dispatch event from 1st, I want detect this change in 2nd.
I did everything as in Redux docs about Store subscribing : https://redux.js.org/api/store#subscribe. Unfortunatelly, it's not working for me.
This is my 1st react project.
(vue/x is better :] )
import React, {Component} from 'react';
import reducers from '../../reducers'
import { Dropdown } from 'semantic-ui-react'
import {translate} from "../../actions";
import createStore from "../../createStore";
const store = createStore(reducers)
class Component1 extends Component {
componentDidMount() {
store.subscribe(() => console.log(1));
}
updateTexts(lang) {
store.dispatch(translate(lang));
}
render() {
this.dropdown = <Dropdown
onChange={this.updateTexts}
/>
return (
<div className={"lang-switcher"}>
<div className={"select-lang"}>
{this.dropdown}
</div>
</div>
);
}
}
export default Component1
import React, {Component} from 'react';
import axios from 'axios';
import {Animate} from 'react-animate-mount';
import createStore from "../../createStore";
import reducers from "../../reducers";
const store = createStore(reducers);
export default class Component2 extends Component {
componentDidMount() {
store.subscribe(console.log(2));
}
render() {
return (
<div className="box">
{Something}
</div>
);
}
}
I want that Component2 will detect state change done by Component1.
Reducer is working correctly, updates state after dispatching.
If you're using React, you should be using the React-Redux library to handle interacting with the store.
That said, it also looks like you're creating two different store instances, one in each component file. So, Component 2 doesn't know about the store instance in Component 1's file.
Please create a script Store.js, and import for each component.
When you use export, that will create a singleton from your export const:
Store.js
import reducers from '../../reducers'
import createStore from "../../createStore"
export default createStore(reducers)
and use as:
import store from "./Store";
/* REMOVE const store = createStore(reducers); */
I am writing react application and i has dir with actions files my example action file looks like
export const USER_LOADING_START = 'USER_LOADING_START';
export const USER_LOADED = 'USER_LOADED';
export function userLoadingStart() {
return {
type: USER_LOADING_START
};
}
export function userDataLoaded(value) {
return {
type: USER_LOADED,
payload: {
value: value
}
};
}
and in actions dir i have a file named index.js which content is
import * as userActions from './userActions';
let exp = {
...userActions,
};
export default exp;
So in other files i want to import my action creators so i use:
import {userLoadingStart} from './actions';
and it doesn't work but if i write:
import actions from '../actions';
const { userLoadingStart } = actions;
then it is working correctly, so what am i doing wrong ?
i tried
export {
...userActions,
...spinnerActions,
...errorActions
}
and
export exp
but it doesn't compile by webpack
So in other files i want to import my action creators so i use:
import {userLoadingStart} from './actions';
For that to work, it means ./actions must export named values. The issue is that your logic currently bundles everything up and exports it as single named export named default. The easiest way to do that would be for your index to do
export * from './userActions';
to essentially pass everything from ./userActions through as exports of ./actions.