can I use react navigation and redux while keeping them separated? - reactjs

I am trying to write a react native application making use of both redux and react native navigation. However, I do not actually want to save my navigation state in redux. So I just want to keep them separated from each other. I currently have the StackNavigator and that is wrapped in a connect which then is wrapped by the provider.
const mapStateToProps = state => state;
const mapDispatchToProps = dispatch => dispatch;
// need this Higher Order Component so you can pass properties through the root stack
const AppContainer = connect(mapStateToProps, mapDispatchToProps)(RootStack);
export default class App extends Component {
render() {
return (
<Provider store={Store}>
<AppContainer />
</Provider>
);
}
}
Is this implementation possible?

Yes, this is possible, and in fact, encouraged.
Quotation from react-navigation docs:
Some folks like to have their navigation state stored in the same place as the rest of their application state. Think twice before you consider doing this, there is an incredibly good chance that you do not need to do this!. Storing your React Navigation state in your own Redux store is likely to give you a very difficult time if you don't know what you're doing.
By default, Redux and React-Navigation have nothing to do with each other, and in its next release (Fall 2018) support for integrating React-Navigation into your redux state will not be documented or encouraged at all.

Related

Fetch data for the entire app without depending on component logic

There are X routes in the frontend made with React-router and each of them drives to a component.
No matter which route is visited, I need to use some data from an api.
This data is constant through the application. Using Redux I could dispatch an action FETCH_DATA in each React component and manage the logic of fetching in Redux actions.
However, this looks repetitive to me because I would be writing the same logic through all the React components that need data: look for the the data in the store. If it's there take it. If it's not there, dispatch FETCH_DATA.
What is another approach?
You can call that api in the App.tsx i.e. your first component to be rendered in the application. This is the component which actually holds the Routes also.
Consider the following code as an example and change it according to the need of your application:
class App extends React.Component {
ComponentDidMount() {
this.props.callTheApiHere()
}
render() {
return (
<Routes history={this.props.history} />
)
}
}
export default App;
Now each component that any of your Route render have to just get the data from the redux store using mapStateToProps in react-redux Connect
GraphQL offers an elegant solution for this requirement of sharing data across components belonging to different routes.
More information:
https://www.youtube.com/watch?v=p_kqcGW1jkY
Apollo GraphQL (React) Data sharing across components

React-Redux: Why do we need to wrap the component with Provider?

The best practice for using Redux in React application is wrapping the component in a 'Provider' component:
const rootElement = document.getElementById('root')
ReactDOM.render(
<Provider store={store}>
<TodoApp />
</Provider>,
rootElement
)
You can see it in React-Redux documentation: https://react-redux.js.org/introduction/basic-tutorial.
What is the benefit we get from this attitude?
Why not just importing the 'store' inside the 'ToDoApp' component and access 'store' as an imported variable? For example:
import { store } from './store';
class TodoApp extends Component {
constructor(props) {
super(props);
console.log('constructor')
}
render() {
console.log(store.getState());
}
}
The actual point that is happening in the redux, when we are calling the provider: that it is having the store of all the states and the provider does the job to connect the component with the redux or simply you can say that the provider does the job to connect your app with the redux as the author of the redux has not only to design the library for a single framework, it would have so many uses on different platforms, the store is having two things inside (reducers and state) and all the states get an outer layer of provider which connects the app with the redux library.
This is very important to the way react-redux works.
When you use connect over your component, it attempts to get the store from the Provider you set, using React's context mechanism.
It is highly unlikely that you will use Redux in React without using connect, so I would advise that you keep it there.

Mocking Redux store when testing React components?

I'm using React and Redux. I have a component which loads ChildComponent and depending on Redux's state will also load MainComponent
const ChooseIndex = ({ appInitMount }) => {
return (
<>
<ChildComponent />
{!appInitMount && <MainComponent />}
</>
);
};
const mapStateToProps = ({ main }) => {
return {
appInitMount: main.appInitMount
};
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(ChooseIndex);
I'm trying to write a test to check that ChildComponent is loaded:
import React from "react";
import { render } from "react-testing-library";
import ChooseIndex from "../choose-index";
test("ChooseIndex should call ChildComponent", () => {
const wrapper = render(
<ChooseIndex />
);
});
I get this error:
Error: Uncaught [Invariant Violation: Could not find "store" in either
the context or props of "Connect(ChooseIndex)". Either wrap the root
component in a , or explicitly pass "store" as a prop to
"Connect(ChooseIndex)".]
Should I mock Redux by passing an object literal to ChooseIndex? Or should I create a Redux store (as my real application does) for every test?
Try to render your component like this:
render(
<Provider store={store}>
<ChooseIndex />
</Provider>
)
And pass the actual store you use in your app. In this way, you're testing the real logic that you'll use in production. You also don't care what actions get dispatched and what's in the state. You look at what gets rendered and interact with the UI—which is what matters in the end.
Separating the component from Redux and testing the two in isolation is against the whole point of react-testing-library. You want to test your app as a real user would.
If you check out the writing tests section of the redux docs, there is an example of testing a connected component.
when you import it [A redux connected component], you're actually holding the wrapper component returned by connect(), and not the App component itself. If you want to test its interaction with Redux, this is good news: you can wrap it in a with a store created specifically for this unit test. But sometimes you want to test just the rendering of the component, without a Redux store.
In order to be able to test the App component itself without having to deal with the decorator, we recommend you to also export the undecorated component
As with most unit tests, you really want to be testing your components, and not that redux is working correctly. So the solution for you is to export both the component and the connected component, while only testing the component itself, and providing whatever props redux is passing to your component.
import { connect } from 'react-redux'
// Use named export for unconnected component (for tests)
export class App extends Component {
/* ... */
}
// Use default export for the connected component (for app)
export default connect(mapStateToProps)(App)

Writing style in React and Redux about using store or connect()?

Im new to React and have a question about the writing style for React.
The question is that when geting state from redux , which is better or normal writing style.
1) using connect() and mapPropsToState() *react-redux
2) using store and getState()
Now Im using 'connect()' because many tutorials use 'connect()' to pass or get state from Redux.
But I think if these components have children , Props have to be passed into children like without using Redux.
It is killing one of redux's strong point that can get state from any layer(anywhere).
sample code her
index.js
export let store = createStore(reducer);
<Provider store={store}>
<Router history={browserHistory}>
<Route component={parent}>
</Route>
</Router>
</Provider>
render.js
class parent exteds react.Component{
render(){
return(
<child test={this.props.test}/>
)
}
}
class child exteds react.Component{
render(){
return(
<button onChange={this.props.test}/>
or
<store.dispatch(testfunction()>
)
}
}
function mapStateToProps(state) {
console.log(state)
return {...state};
}
function mapDispatchToProps(dispatch) {
return bindActionCreators({
test:testfunction
}, dispatch)
};
export const renderFormGenerator = connect(mapStateToProps,mapDispatchToProps)(render);
As your application grows it will be better to use react-redux ,over manually passing store to all of your individual components.
That said , there is a small change required in your connect . The component that you wish to received your action creators should be in the place of your render
i.e Instead of this
connect(mapStateToProps,mapDispatchToProps)(render)
do this
connect(mapStateToProps,mapDispatchToProps)(myComponent)
This way you can access your action creators in myComponent like this.props.myAction()
I agree with your concern that if it is used this way , you will have to manually pass the action again as props to the children .
But that can be easily resolved by creating a Child container and using connect again . connect(mapStateToProps,mapDispatchToProps)(myChildComponent)
i'd recommend go through this excellent article on Smart Vs Dumb Components by Dan Abramov.

ES6 React Redux syntax clarification

I'm new to ES6 and Redux. Im looking at some code and trying to understand what is going on in this new ES6 syntax.
I feel like this may be simple but i am not understanding it and it might help someone else in a similar position to me.
i want to know how the following code is creating a react element. im familiar with the React.createClass method, but that doesnt seem to be stated here or at least not explicitly. i can see React is imported, but it isnt mentioned in the rest of the code. so then how the FileTable get turned into a react component?
I can see the const variable FileTable seems to contain what would usually go in the render method of React.createClass, but if that is the case, where would methods like componentDidMount, componentDidUpdate, etc be defined?
Any help on this is greatly appreciated.
import React, { PropTypes } from 'react';
import { connect } from 'react-redux';
import * as actions from '../actions';
const FileTable = ({ fileList, getFileList}) => {
return (
<ul className="filterable-table">
{fileList.map((file)=><li>{file.fileName}</li>)}
</ul>
);
};
FileTable.propTypes = {
fileList: PropTypes.array,
};
const mapStateToProps = (state) => {
return {
fileList: state.fileList
};
};
const mapDispatchToProps = (dispatch) => {
return {
getFileList: () => dispatch(actions.getFileList())
};
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(FileTable);
You can create react components in 3 ways - React.createClass, ES6 class or
Stateless (pure) function component. This is a stateless component, which means that it doesn't have state, life cycle methods (like componentDidMount or componentDidUpdate), and refs, and as you surmised it's similar to the render method of a react class.
Whenever you need a purely representational dumb component you can use a stateless component, due to its brevity. It goes nicely with redux, as the connect create a smart component that wraps the stateless method.
Regarding performance, stateless components don't have any performance gain over ES6 class component without state. However, Facebook stated that in the future there will be some optimizations.
It doesn't have to be declared here as a React component; React knows about pure functions.
Pure functions don't need to inherit from Component. They're not appropriate for all component types, but for simple HTML renders they're preferred (e.g., see eslint-plugin-react prefer-stateless-function.
Pure functions don't have component lifecycles, associated methods, etc.

Resources