I have a react-native app that contains two applications in it. These two parts have their own UI and state. When users open up the app want to sign up, they can select how they wanna use this application.
I like to encapsulate state these two parts from each other.
My idea was to have two providers and render them conditionally, but don't know this is a good practice and have any edge cases or not.
const rule = 'first' // or 'second'
rule === 'first' ?
<Provider store={firstStore}>
// first app related screens
</Provider>
:
<Provider store={secondStore}>
// second app related screens
</Provider>
Who can I encapsulate the state for these two parts perfectly?
Separating UI and Data is a good idea. You can't have two providers though, you need to put these into 2 separate reducers. So, you can have something like this (code is just a snipped example, you'd replace with your own of course).
import { combineReducers } from 'redux';
import carousels from './dataCarouselsReducer';
import filterIntents from './filterIntents';
import generatedImages from './generatedImages';
import indexing from './indexing';
import { nlpIntentsReducer } from './nlpIntents';
import nullSpaceData from './nullSpaceData';
import { searchReducer } from './search';
import similarityIntents from './similarityFilterIntents';
import uiCarouselsReducer from './uiCarouselsReducer';
import user from './user';
import workflows from './workflows';
const rootReducer = combineReducers({
data: {
user,
search: searchReducer,
nullSpaceData,
similarityIntents,
carousels,
indexing,
generatedImages,
workflows,
},
ui: {
filterIntents,
nlpIntents: nlpIntentsReducer,
uiCarouselsReducer,
},
});
export default rootReducer;
Related
I am fairly new to React and still wrapping my head around custom-hooks. I cam across a code where a custom hook was created to handle the component imports.
useComponentPalette.js
import {TodoEditor} from './components/TodoEditor'
import {TodoItem} from './components/TodoItem'
import {TodoList} from './components/TodoList'
import {CheckBox} from './components/CheckBox'
const defaultComponents = {
TodoEditor,
TodoItem,
TodoList,
CheckBox
}
export function useComponentPalette(){
return defaultComponents
}
And then in order to use the hook,
const {TodoItem, TodoList, Checkbox } = useComponentPalette()
My Question :- Does this approach provides any advantage over the regular imports in the component ? or this is an anti-pattern ?
How I usually import the components is as follows
import {TodoEditor} from './components/TodoEditor'
import {TodoItem} from './components/TodoItem'
import {TodoList} from './components/TodoList'
import {CheckBox} from './components/CheckBox'
function App(){
return(
<>
<TodoList/>
</>
)
}
It's not a good idea to use react hooks like this you can get the same result without react hook
// first file name.js
import {TodoEditor} from './components/TodoEditor'
import {TodoItem} from './components/TodoItem'
import {TodoList} from './components/TodoList'
import {CheckBox} from './components/CheckBox'
export default {
TodoEditor,
TodoItem,
TodoList,
CheckBox
}
//component file
import * as Component form 'first file name';
//<Component.TodoEditor/>
//or
import {TodoEditor} form 'first file name';
The way that I use react-hooks is for making my code more dry and increase it's readability, so react-hooks is not good fit for this kind of usage.
Hi #Sachin,
In my option, React JS use hook to manage reuse stateful logic between components. In other word, Hooks do well to encapsulating state and share logic. If you want to do some stateful logic or condition base logic with these components, then it's fine with that. But if you are using just without condition in the given components. Then, This Is useless for making the custom hook. You can do that without a custom hook in a simpler way.
Here is a simple way to do that:-
In components folder. I create index file, this is the entry point of all my exporting components
In that file. I export all my components, as you can see.
I use that components like this. It much better way. In my option.
import { Header, Footer, Sider } from "./components"
before using react custom hooks, we should be aware of the rationale behind it.
Customs hooks functionality was provided to reuse stateful logic. If logic doesn't require any state, we will use simple functions and if it is about components only there there are different patterns for making code general and scaleable.
So, there is no usage of custom hook in above case at all. For me, I would go with the following code for above scenario:
// components/index.tsx
import {Todo} from './todo'
import {CheckBox} from './components/CheckBox'
export {
Todo,
CheckBox
}
// componentns/todo/index.tsx
import {Editor} from './Editor'
import {Item} from './Item'
import {List} from './List'
const Todo = {
Editor,
Item,
List
}
export default Todo;
and usage will be like
import { Checkbox, Todo } from "components"
...
<Checkbox ... />
<Todo.List ...>
<Todo.Item ... >
</Todo.Editor ... />
</Todo.Item ... >
</Todo.List>
...
P.S Usage can be different based upon the logic of components, just giving an hint how we can patterns to serve our purpose.
Hope it helps.
I have a scenario with 2 components:
App
People
I want to test if People gets rendered 10 times inside App. So, I'm trying to test that using Jest. So far, I did this on my src/App.test.js:
import React, { Component } from "react";
import People from "./components/People";
import App from './App';
test('Total people = 10', () => {
expect(App).find(People).toHaveLength(10);
});
But I get a message saying:
TypeError: expect(...).find is not a function.
How can I test how many times a component gets rendered inside another component using React and Jest? Can anyone help me?
For testing react components first you need to render them, there are some tools for doing that, but since your reasoning in this test is to check how many times a component has been rendered inside another component, enzyme does a good job with its shallow method.
import React from "react";
import App from "./App";
import People from "./components/People";
import { shallow } from "enzyme";
it("Total people = 10", () => {
const wrapper = shallow(<App />);
expect(wrapper.find(People)).toHaveLength(10);
});
You'll need to set up enzyme in your project first, read the docs for more details.
The current trend in testing is to check for the things the user actually sees in the page, so most people is using react-testing-library, It'll be good for you to check it out
If you ever switch to react-testing-library, you might write the test something like this:
import React, { Component } from "react";
import App from './App';
import {render} from "#testing-library/react";
test('Total people = 10', async () => {
const { getAllByText } = await render(<App />);
expect(getAllByText('string_in_People')).toHaveLength(10);
});
Basically you'd use one of the library's built-in getAllBy... query methods to query for all instances of an element that appears exactly once in each instance of your <People /> component. The resulting set's length will equal the number of <People /> instances on the page.
TL;DR: Configuring the Redux Toolkit store in React Native for HMR properly refreshes app on changes, but reducer behaviour does not change!
As seen in the React Native Reloading Announcement, HMR is supported for Redux within React Native, but the steps listed do not appear to work anymore. I have configured everything as mentioned in the announcement; however, the reducer reloading does not actually seem to change anything. When I edit a reducer, the app updates (reloading notification) but the reducer behaviour does not change!
// store/rootReducer.js
import { combineReducers } from "#reduxjs/toolkit";
import eventsReducer from "./slices/events";
import peopleReducer from "./slices/people";
const rootReducer = combineReducers({
events: eventsReducer,
people: peopleReducer,
});
export default rootReducer;
// store/index.js
import { configureStore } from "#reduxjs/toolkit";
import rootReducer from "./rootReducer";
const store = configureStore({
reducer: rootReducer,
});
if (process.env.NODE_ENV === "development" && module.hot) {
module.hot.accept(() => {
const newRootReducer = require("./rootReducer").default;
store.replaceReducer(newRootReducer);
});
}
export default store;
// App.js
import React from "react";
import { Provider } from "react-redux";
import store from "./store";
const App = () => {
return (
<Provider store={store}>
// ...ThemeProvider, Navigation scenes, etc
</Provider>
);
};
export default registerRootComponent(App);
Any ideas why this may be happening? I've been searching for related questions but cannot find anything from the recent past (ie. this year). Any older issues do not work either. My understanding is that I do not have to handle App HMR, as this is handled automatically by React Native. The announcement above makes it appear that adding HMR to Redux in React Native is super easy; however, it is has proven to not be the case.
In a page I need to have multiple modals, and I did this
import ApproveModal from '~/components/common/modal'
import RejectModal from '~/components/common/modal'
this.setState({ openApproveModal: true })
{openApproveModal && <ApproveModal />
this.setState({ openRejectModal: true })
{openRejectModal && <RejectModal />
Not sure this is the correct way to do it but I saw possible of having duplicated codes, what if I have 3-4 actions, I need to import 4 confirmation modals?
In your modal component, just export multiple instances of various modals:
export { ApproveModal, DeclineModal };
Then just import them using the very useful destructuring pattern (more here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment):
import { ApproveModal, DeclineModal } from '~/components/common/modal';
I am using React-Navigation where I am using functionality of custom drawer by using contentComponent of React-Navigation.
const DrawerNavigation = DrawerNavigator({
DrawerStack: { screen: DrawerStack }
}, {
contentComponent: DrawerComponent,
drawerWidth: 300
})
Here DrawerComponent is my custom navigation drawer where I have used custom navigation items like username, profile picture, email address and other menus.
Now whenever user updates their profile I want to refresh my DrawerComponent, I am not able to find any way to do it. Can anybody suggest me a good way to implement this?
Couple of options here, and all are tight to how you want to achieve your state management.
First, one solution would be to have the your user state in the component creating the DrawerNavigator, and pass it down to your custom drawer component. This presents the disadvantage of having to recreate your navigator on state change and create a blink. I do not advice to use this solution but it's worth mentioning as a possibility.
You could also use a React Context, have your user state in a top level component, create a provider passing it the user as the value and make your drawer a consumer of this context. This way, every time the user changes your drawer component would re-render.
What I use personally is Redux to connect my Drawer directly to my global state. It involves a bit of setup but it's worth it in the end. A root component could look like this:
import React from 'react'
import { Provider } from 'react-redux'
export default () => (
<Provider store={store}>
<App />
</Provider>
)
Where store is the result of:
import { createStore, combineReducers } from 'redux'
import reducers from './reducers'
const store = createStore(combineReducers(reducers))
Your reducers are going to be the state of your app, and one would be dedicated to your user data.
Then your Drawer component could be:
import React, { Component } from 'react'
import { View, Text } from 'react-native'
import { connect } from 'react-redux'
#connect(({ user }) => ({ user }))
class Drawer extends Component {
render () {
const { user } = this.props
return (
<View>
<Text>My name is {user.name}</Text>
</View>
)
}
}
export default Drawer
Now, every time you change your user reducer, this Drawer component will re-render.
There is a few things your should know about Redux, so you should probably read up a bit the Getting Started docs.
I know it is a old question now but you can do this by importing the code like
import DrawerView from '../Drawer/Drawer'
contentComponent: DrawerView
then in the DrawerView file
class DrawerView extends Component {
render(){
return(
//Do your stuff here
)
}
}
export default DrawerView;
for more info please visit this link and thank to Kakul Gupta for this https://codeburst.io/custom-drawer-using-react-navigation-80abbab489f7
The easiest way to change menus without using redux is, using createSwitchNavigator.
https://reactnavigation.org/docs/en/auth-flow.html