React Native: use mobx store state from another store - javascript

I was wondering how can I use a n observable from one store inside another store class, for example use userStore inside mapStore.
Now I will show you how I initiate stores and use them in my functional components:
/contexts/index.js
import React from 'react'
import { configure } from 'mobx';
import { UserStore } from '../stores/UserStore.js'
import { MapStore } from '../stores/MapStore.js'
export const storesContext = React.createContext({
userStore: new UserStore(),
mapStore: new MapStore(),
});
configure({ enforceActions: "observed" });
/hooks/use-stores.js
//hooks/use-stores.js
import React from 'react'
import { storesContext } from '../contexts/index.js'
export const useStores = () => React.useContext(storesContext);
Inside my functional components I access like this:
import { useStores } from '#hooks/use-stores';
...
const { mapStore,userStore } = useStores();
An example class, UserStore
export class UserStore
{
constructor()
{
makeAutoObservable(this);
user = false;
}

Related

Couldn't access state in vuex 4

I'm using vuex v4 with composition api. The problem is I couldn't access store states in components but I can see them in vue-devtools. When I wanna access store state it gave me undefined.
store/index.ts:
import { InjectionKey } from "vue";
import {
createStore,
createLogger,
Store,
useStore as vuexUseStore,
} from "vuex";
import { ConfigStateType } from "./config/state";
import config from "./config";
export enum ModuleTypes {
CONFIG = "CONFIG",
}
export interface StateInterface {
config: ConfigStateType;
}
export const key: InjectionKey<Store<StateInterface>> = Symbol();
export const store = createStore<StateInterface>({
modules: {
[ModuleTypes.CONFIG]: config,
},
strict: debug,
});
export function useStore() {
return vuexUseStore(key);
}
vue js main.ts:
import { store, key } from "./store";
createApp(App).use(store, key).use(router).mount("#app");
In my component:
import { useStore } from "#/store";
setup() {
const store = useStore();
const recaptchaSiteKey = computed(
() => store.state.config.googlerecaptcha_site_key
);
return {
recaptchaSiteKey
}
}
always recaptchaSiteKey returns undefined, but in vue-devtools states are filled.
vuex devtool:

Mobx store in react doesn't rerender components

I'm trying to understand mobx. After annotations caused a lot of trouble, I decided to use a global store as described here. My store looks like this:
import {
makeObservable,
observable,
action
} from "mobx";
class Store {
constructor() {
makeObservable(this, {
fetchWorkouts: action,
user: observable,
allWorkouts: observable,
selectedWorkout: observable,
currentStep: observable,
setUser: action
})
}
user = {
uid: null,
email: null,
name: null
}
allWorkouts = []
selectedWorkout = {}
currentStep = 0
fetchWorkouts() {
}
setUser(newUser) {
this.user = newUser;
}
}
const store = new Store()
export default store;
My new user comes directly from the login, which looks like this:
import {Button} from "semantic-ui-react";
import {useHistory} from "react-router-dom"
import React from 'react';
import store from "../../context/Store";
import {toJS} from "mobx";
export default function SubmitLogin(props) {
let history = useHistory();
// eslint-disable-next-line react-hooks/exhaustive-deps
const loginUser = async () => {
let bodyObj = {
email: props.email,
pw: props.password
}
let queryString = "http://localhost:3001/user/login/" + bodyObj.email + "/" + bodyObj.pw;
await fetch(queryString).then(response => response.json()).then(json => store.setUser(json)).then(() => console.log(toJS(store.user))).then(() => history.push("/"));
}
return (
<>
<Button className={"loginRegisterButton"} onClick={loginUser}>Submit</Button>
</>
)
}
To test everything, I am trying to display the uid in my header like this:
import React, {Component} from 'react';
import {Link} from "react-router-dom";
import store from "../context/Store";
class Toolbar extends Component {
render() {
return (
<div id={"toolbarDiv"}>
<p style={{color: "white"}}>{store.user.uid}</p>
</div>
);
}
}
export default Toolbar
However, even after I receive the uid from my server and can print it in my login component, I assume that the data gets correctly assigned to the user variable in the store. Unfortunately, after pressing the sign in button and getting redirected to "/", there is nothing in the toolbar. How can I access the variables correctly?
I think you still need to wrap Toolbar and SubmitLogin in an observer call:
import React, {Component} from 'react';
import {Link} from "react-router-dom";
import { observer } from "react-mobx";
import store from "../context/Store";
class Toolbar extends Component {
render() {
return (
<div id={"toolbarDiv"}>
<p style={{color: "white"}}>{store.user.uid}</p>
</div>
);
}
}
export default observer(Toolbar);
Ref: https://mobx.js.org/react-integration.html

How do I get any form value from anywhere in my app in redux-forms v7

The closest to doing this is reduxForm().getFormState() of which it's not well documented
You'll want to use the formValueSelector that is exported from redux-form. While you can dive directly into the state tree and pull things out for yourself, using the selector exported by redux-form means that you aren't taking a dependency on any implementation details of redux-form.
You use it like:
import React from 'react';
import { formValueSelector } from 'redux-form';
class App extends React.Component {
// ...
}
const formName = 'myForm'; // Name of form you want
const myFormValueSelector = formValueSelector(formName);
const mapStateToProps = state => ({
name: myFormValueSelector(state, 'name') // selects the name field value
});
export default connect(mapStateToProps)(App);
You can find documentation for this method here
Form values will be available on the redux store. You can get it from any app components.
Mini example,
index.js,
import React from 'react';
import ReactDOM from 'react-dom';
import thunk from 'redux-thunk';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import { combineReducers } from 'redux';
import { reducer as formReducer } from 'redux-form';
import App from './src/components';
const rootReducer = combineReducers({
form: formReducer,
});
const createStoreWithMiddleware = applyMiddleware(thunk)(createStore);
const store = createStoreWithMiddleware(reducers);
ReactDOM.render(
<Provider store={store}>
<App />
<Provider>
, document.querySelector('.root'));
app.js,
import React, { Component } from 'react';
import { change, Field, reduxForm } from 'redux-form';
import { connect } from 'react-redux';
class App extends Component {
...
render() {
console.log(this.props.forms); // This fill print information about all of your app forms
return <div />;
}
}
function mapStateToProps(state) {
return {
forms: state.form;
}
}
export default reduxForm({
form: 'someForm',
})(connect(
mapStateToProps,
null
)(App));
In app.js, console.log will print form data like this,
{
someForm: {...someForm props},
someOtherForm: {...someOtherForm props},
}

How to define props for react-navigation with Flow

I am working on a simple React Native App, and have decided to user react-navigation. I have also decided to go with Flow for static type checking. What I can't figure out, is how to define navigation related props with Flow.
e.g. I define my App.js to use StackNavigator like so:
import StackNavigator from 'react-navigation';
import Main from './app/containers/Main';
const App = StackNavigator({
Main: { screen: Main },
});
export default App;
then I define my Main class, but I don't know how to reference react-navigation in my props:
// #flow
import React, { Component } from 'react';
import { View, Text } from 'react-native';
type Props = {
navigate: ????
};
type State = {};
class Main extends Component<Props, State> {
...
}
According to https://github.com/react-navigation/react-navigation/issues/3643
import { NavigationState, NavigationScreenProp } from 'react-navigation';
type Props = {
navigation: NavigationScreenProp<NavigationState>
};
Import NavigationScreenProp from react-navigation:
// #flow
import React, { Component } from 'react';
import { View, Text } from 'react-native';
import { NavigationScreenProp } from 'react-navigation';
type Props = {
navigate: NavigationScreenProp<{}>
};
type State = {};
class Main extends Component<Props, State> {
...
}
react-navigation has a flow file. Maybe you can import from there or just copy-paste
https://github.com/react-navigation/react-navigation/blob/master/flow/react-navigation.js#L72
To prevent Cannot import the type NavigationState as a value. Use the import type instead.
// #flow
import React, { Component } from 'react';
import type { NavigationState, NavigationScreenProp } from 'react-navigation';
type Props = {
navigation: NavigationScreenProp<NavigationState>
}
type State = {}
class Main extends Component<Props, State> {
...
}
You can also add below to .flowconfig to prevent flow-typed/npm/redux-devtools-extension_v2.x.x.js:23:33
[lints]
deprecated-utility=off

Unit Test React-Redux Connected Components?

I am using Mocha, Chai, Nock, Sinon, Webpack for Unit tests.
I used the following link to test my actions, reducers
http://redux.js.org/docs/recipes/WritingTests.html
I was able to test dumb components from other react articles. Currently I am trying to test my smart component and i get errors.
my react-redux component (SmartComponent.js)
import React, { Component, PropTypes } from 'react'
import ReactDOM from 'react-dom'
import * as componentActions from '../actions/componentActions'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
export class SmartComponent extends Component {
constructor(props) {
super(props)
this.updateText = this.updateText.bind(this)
}
updateText(event){
this.props.actions.updateText(event.target.value)
}
render() {
return(
<div>
<input type='text' onChange={this.action1} placeholder='type something'
/>
<span>{this.props.inputText}
</div>
)
}
}
function mapStateToProps(state) {
const inputText = state.inputText
return{
inputText
}
}
function mapDispatchToProps (dispatch) {
return {
actions: bindActionCreators(componentActions, dispatch)
}
}
const SmartComponentContainer = connect(
mapStateToProps,
mapDispatchToProps
)(SmartComponent)
module.exports = SmartComponentContainer
this is my unit test file
import setupDom from '../setup'
import chai from 'chai'
import jsxChai from 'jsx-chai'
import React, { Component, PropTypes } from 'react'
import ReactDOM from 'react-dom'
import TestUtils from 'react-addons-test-utils'
import {Provider} from 'react-redux'
import {findAllWithType, findWithType, findWithClass} from 'react-shallow-testutils'
import SmartComponentContainer,{SmartComponent} from "../containers/SmartComponent"
chai.use(jsxChai)
let expect = chai.expect
/**
* Mock out the top level Redux store with all the required
* methods and have it return the provided state by default.
* #param {Object} state State to populate in store
* #return {Object} Mock store
*/
function createMockStore(state) {
return {
subscribe: () => {},
dispatch: () => {},
getState: () => {
return {...state};
}
};
}
function setup() {
const storeState={
inputText : ''
}
let renderer = TestUtils.createRenderer()
renderer.render(<SmartComponentContainer store={createMockStore(storeState)} />)
let output = renderer.getRenderOutput()
return {
output,
renderer
}
}
function setUpComponent(){
const props ={}
let renderer = TestUtils.createRenderer()
renderer.render(<SmartComponent {...props} />)
let output = renderer.getRenderOutput()
return {
output,
renderer
}
}
describe('test smart component container',()=>{
it('test input value change',()=>{
const {output,renderer} = setup()
console.log(output)
// when i do the console.log output here , i am getting my actions and state variable but i do not get the html inside render method
})
it('test component',()=>{
const {output,renderer} = setUpComponent()
console.log(output)
})
})
The first test is successful and i prints the output with actions and state variables but not able to get render html printed.
The second test throws an error "TypeError: Cannot read property 'propTypes' of undefined" . I want access to html and have ability test like with normal component
expect(output.props.children[0].type).to.equal('input')

Categories