React-native Redux counter example: explain about reducer - javascript

I am learning react-native and redux from this article,
https://github.com/alinz/example-react-native-redux/tree/master/Counter, and I want to understand why inside folder reducers, there is an index.js with content as below:
import counter from './counter';
export {
counter
};
I dont understand why we need this, since in the same folder reducers, there is counter.js with content as follow
export default function counter(state = initialState, action = {}) {
...
}
it already export default counter, why does index.js do it again

If your application grows with lots of reducers, you can 'import nameHere from reducers'. (it is just a convenience). Also, your code is easier to 'refactor' ussually, since you don't need to change the actual import, but you can for instance import multiple from this same file.
// this is preferred
import { ScalesReducer, BoxReducer } from './reducers';
// does the same, takes more space (more distraction in your code)
import ScalesReducer from './reducers/ScalesReducer';
import BoxReducer from './reducers/BoxReducer';

Related

How to wrap every exported comopnent with HOC?

I need to add to ALL of my React function components the possibility to add [data-test-id] attribute for testing purposes. To achieve that I created withTestId() HOC which adds optional prop testId to wrapped component and when it's defined it adds [data-test-id] to final HTML.
So when I define component like:
<ExampleComponent testId="example" />
it returns:
<div data-test-id="example" />
The only problem I have is to apply it to every component without the necessity to wrap it individually in every component. So instead of writing code like:
function ExampleComponent() { ... }
export default withTestId(ExampleComponent)
I would like to wrap all of my exports in my index.ts file, which right now looks like this:
export { default as ExampleComponent } from "./ExampleComponent";
export { default as ExampleComponent2 } from "./ExampleComponent2";
...
How can I achieve this?
I see two ways of doing this; One dynamic way, making the user-code of your library a bit more convoluted. with you being able to change the implementation easily and another one with a bit more boilerplate code, keeping the user-code as it is.
I haven't tested their behavior regarding tree-shaking when bundling the code.
Using destructing in user-code
This allows to add / remove things from your main component export file without having to worry about additional boilerplate in your library. The higher-order-component can be switched on/off easily. One caveat: The user code needs to use destructuring to retrieve the components.
Your new index.ts file would look like this, while I've called your previous index.ts file components.ts in the same directory:
import * as RegularComponents from "./components";
import withTestId from "./with-test-id";
const WithTestIdComponents = Object
.keys(RegularComponents)
.reduce((testIdComps, key) => {
return {
...testIdComps,
[key]: withTestId(RegularComponents[key])
};
}, {});
export default WithTestIdComponents;
To use it in your application code:
import MyComponents from "./components/tested";
const { Component1, Component2, Component3, Component4 } = MyComponents;
This uses the default export to make it look like you have all components in one place, but since you cannot destructure exports directly, you need this second step to get the correct components out of it.
Add boilerplate to the export file
Since there is an index.ts file with all the components exported in the library, one could import/rename each component and re-export them with withTestId and their name:
import withTestId from "./with-test-id";
import { default as TmpComponent1 } from "./component1";
import { default as TmpComponent2 } from "./component2";
import { default as TmpComponent3 } from "./component3";
import { default as TmpComponent4 } from "./component4";
export const Component1 = withTestId(TmpComponent1);
export const Component2 = withTestId(TmpComponent2);
export const Component3 = withTestId(TmpComponent3);
export const Component4 = withTestId(TmpComponent4);
This way, imports can be used as before:
import {
Component1,
Component2,
Component3,
Component4
} from "./components";
I'd argue that using index files already is some kind of boilerplate and this approach adds to it. Since the user code does not need any changes, I'd favor this approach.
In one of our projects, we have used a custom takeoff script to create this kind of boilerplate for us, whenever we generate a new component.
Examples
Here is a code sandbox to see both approaches.

Is it possible to import and use a react-redux component from vanilla javascript

I have two applications, one of them is written in vanilla javascript with html and css. The other one is a react + redux application.
Is it possible to import and use the components from my react + redux application inside my vanilla javascript application without introducing a dependency on react and redux?
Short answer, yes , depending how you've written the code. Namely, assuming you are using ES6 Modules, or using a transpiler that will handle them as such.
Firstly, remember that react-redux is just an implementation of redux for react. Redux works fine by itself.
Assuming what you are talking about is reusing your reducers and action creators, then that will be fine - as all they are are pure functions.
For example say your app looks like:
index.js
import React from "react";
import store from "./store";
import {createUser} from "./actions";
import { Provider } from 'react-redux';
//etc.
store.js
import { createStore } from 'redux'
import rootReducer from '../reducers'
export default function() {
return createStore(rootReducer);
}
actions.js
export function addUser(name) {
return {
type: "ADD_USER",
payload: name,
}
}
reducers.js
export default function (state ={}, action) {
return {
value: action.payload
}
}
In this scenario, lets say you want to reuse the action, and the reducer.
Then you can just import the functions from these modules. ESM modules are smart enough to just import what they need.
On the otherhand, say you were importing the createStore (default) method, then you would also be importing the dependency on redux.

JS `import` is undefined, potentially circular import issue?

Preface
I'm using create-react-app to generate an application.
Problem
TodoList === undefined
Code
components/index.js
export { default as App } from './App/App.js';
export { default as TodoList } from './TodoList/TodoList.js';
containers/index.js
export { default as VisibleTodoList } from './VisibleTodoList.js';
components/App/App.js
import { VisibleTodoList } from '../../containers/index.js';
containers/VisibleTodoList.js
import { TodoList } from '../components/index.js';
components/TodoList/TodoList.js
export default function TodoList({ todos, onTodoClick }) { ... }
TodoList is now undefined. I believe it may have something to do with the fact that I have some sort of circular issue.
The thing is, if inside containers/VisibleTodoList.js I import using the following method, everything works fine.
import TodoList from '../components/TodoList/TodoList.js';
What is so special that breaks the import, if I try to import using a 'middleman' (the components/index.js file).
Full code
I have created a CodeSandbox that contains my full code, as it stands in my application. The application is pretty simplistic, but more complicated than I have outlined here.
https://codesandbox.io/s/m54nql1ky9
The problem is caused by the order of exports in your components/index.js file.
export { default as App } from './App/App.js';
export { default as TodoList } from './TodoList/TodoList.js';
Since App.js imports VisibleTodoList which needs to import TodoList and pass it to the redux connect function before it can export itself, you end up with a conflict.
I'm not sure if this is a implementation quirk of babel, or if this is a logical result from how the ES import spec is defined.
In any case, changing the order of exports fixes the bug.
export { default as TodoList } from './TodoList/TodoList.js';
export { default as App } from './App/App.js';
As a rule of thumb, if you can't refactor your files to avoid the import loop, you should put the outer layer component last in the list, since it might rely on imports higher up in the list.
Full working codesandbox here: https://codesandbox.io/s/74mlwnwyy1

ES6 modules: How to automatically re-export all types in the current directory from index.js?

I have lots of code like this scattered around index.js files throughout my React Native project:
import Restaurant from './Restaurant';
import Store from './Store';
import Vineyard from './Vineyard';
import Wine from './Wine';
export {
Restaurant,
Store,
Vineyard,
Wine
};
It's very repetitive and tedious to write out. Is there a way I can automatically re-export all of the other files in the current working directory from index.js? (note I'm also using Flow in my project so any solution should preserve the type information it can infer.)
Thanks.
export * from './Restaurant';
export * from './Store';
By using the above syntax, you can access all exported properties from each component and export them directly.
This is a common pattern when you grouping all Actions in each individual Action file inside index.js and exporting them directly. You can have a look at the github repo
You can also use this pattern if you'd like:
export { default } from './Comp'
export { default as CompHeader } from './CompHeader'
export { default as CompContent } from './CompContent'
// Usage
import Comp, { CompHeader, CompContent } from './component/Comp'

React-Native - Redux - access to store

I got a big problem for my project and cannot continue without that.
I have 2 screens : for example one for main page and another for second page.
So, there are 2 sections in my Navigation Drawer.
In main page, I save state into my store and get this:
object: {
fruits: ['apple', 'orange', 'banana'],
drinks: ['mojito', 'colar']
}
I want to access to the store of mainPage so in my second page I did :
store.getState().
And I got
object: {
fruits: [],
drinks: []
}
So I got the same state but it's empty. I don't understand why. If you have any ideas. I can maybe later show you more my code if necessary.
My store :
import { createStore, applyMiddleware } from 'redux';
import logger from 'redux-logger';
import thunk from 'redux-thunk';
import { composeWithDevTools } from 'remote-redux-devtools';
import reducer from '../reducers';
const middleware = applyMiddleware(thunk, logger);
export default function configureStore(initialState) {
const store = createStore(
reducer,
initialState,
middleware
);
return store;
};
For each component, there are a container? Or only one container for all components? I don't really understand that. Sorry I'm new to React-Native, Redux and navigation drawer. It's hard for me to make them works all together..
Maybe the problem is in connect() but I connected them together normally
Sorry it's a little late and hard for me to say anything without seeing your reducers. Within your mainPage, you need to dispatch actions which will trigger a concat to the fruits and drinks array. You can also move your store declaration outside the function declaration and export it. Importing and calling it in other screens will allow you to have access to it, but this isn't the recommended way. The standard way is to call mapStateToProps method and connect that to your component.

Categories

Resources