I have to projects where I'm using the useContext() react function to create a user auth context. I'm using the same exact js file in both projects. For some reason in my new project the create context returns a slightly different object than the object in the old projects even though the initialization is identical. This is causing the createContext() function in the new project to return null. The context object in the first project has a calculateChangedBits item which might play a role in I have a theory that this might be due to some sort of react update. Here what is inside the js file. I also added two pictures to show the authUsercontext output for both the old and new project. The old project is the one with calculateCHangedBits in it.
(https://i.stack.imgur.com/kOeyt.jpg)](https://i.stack.imgur.com/kOeyt.jpg)](https://i.stack.imgur.com/gYUSw.jpg)](https://i.stack.imgur.com/gYUSw.jpg)
import { createContext, useContext, Context } from 'react'
const authUserContext = createContext({
authUser: null,
loading: true,
calculateChangedBits: null,
signInWithEmailAndPassword: async () => {},
createUserWithEmailAndPassword: async () => {},
signOut: async () => {}
});
export const useAuth = () => useContext(authUserContext);
I have isolated the issue to be with the return of the create context but I do not understand why the new useContext function returns null
I have several components where I added a analyticsProvider to track usage. In each one of these, I'm using an useEffect hook and importing useAnalytics:
import { useAnalytics } from '#framework/component-analytics';
const { trackView } = useAnalytics();
useEffect(() => {
trackView(`/liveTraffic`, 'liveTrafficPage');
}, [trackView]);
I also have a AnalyticsProvider at the root of the application that passes all the necessary config to the child consumers (ie. useAnalytics).
I'm running into an issue when running tests: 'useAnalytics' must be called from inside an '<AnalyticsProvider>', or must be provided with an 'eventManagerConfiguration' argument.
What is the best way to pass the component needed and related configuration in my tests? I'm fairly new to React and struggling to figure out what to use. I've looked into wrapping the components but it's not working.
describe('has no liveTraffic list items', () => {
const component = shallow(analyticsWrapper(<LiveTrafficPage {...props} />));
it('should NOT render LiveTrafficListing', () => {
expect(component.update().find(LiveTrafficListing).length).toEqual(0);
});
});
I am new to React, and when I was reading about the docs, I found there were two ways to implement React components, functional-based and class-based. I know before React 16.8 it's not possible to manage state in functional components, but after that there is React Hooks.
The problem is, there seems to be one restriction for React Hooks, they can only be used inside functional components. Take a server-client as an example, which needs to change an isAuthenticated state while 401 received.
//client.js
import { useUserDispatch, signOut } from "auth";
export function request(url, args) {
var dispatch = useUserDispatch();
return fetch(url, args).then(response => {
if (response.status === 401) {
logout(dispatch);
}
}
);
//auth.js
import React from "react";
var UserStateContext = React.createContext();
var UserDispatchContext = React.createContext();
function userReducer(state, action) {
...
}
function UserProvider({ children }) {
var [state, dispatch] = React.useReducer(userReducer, {
isAuthenticated: false,
});
return (
<UserStateContext.Provider value={state}>
<UserDispatchContext.Provider value={dispatch}>
{children}
</UserDispatchContext.Provider>
</UserStateContext.Provider>
);
}
function useUserState() {
return React.useContext(UserStateContext);
}
function useUserDispatch() {
return React.useContext(UserDispatchContext);
}
function signOut(dispatch) {
dispatch({});
}
export { UserProvider, useUserState, useUserDispatch, loginUser, signOut };
The client code above will produce error "Hooks can only be called inside of the body of a function component".
So maybe I have to move line var dispatch = useUserDispatch() upward to the component where request is called, and pass dispatch as props to request.
I feel this is not right, no only request is forced to care about some meaningless(to it) dispatch, but also this dispatch will spread everywhere a component needs to request.
For class-based components, this.state doesn't solve this problem either, but at least I can use mobx.
So are there some other ideal ways to solve this problem?
I came at this point too. Long story short you need to use Redux and Thunk with Async Logic, as described in detail with examples in the link below [1] if you want to do all of the stuff by hand on your own.
[1] https://redux.js.org/tutorials/essentials/part-5-async-logic
There is another solution that gives out-of-the box experience with Asynchronous API (can work with OpenAPI and GraphQL, handles request, provides caching with lifecycle, etc) wrapping stuff from [1] and its called RTK Query [2].
[2] https://redux-toolkit.js.org/rtk-query/overview
Diagram below explains [1] process visually.. but I think RTK Query [2] wraps everything in one place and could be better solution. There is a Quick Start Guide [3]. I will give it a try :-)
[3] https://redux-toolkit.js.org/tutorials/rtk-query/
Mobx and hooks are very similar in implementation. Both use a render context that is in a sense "global". React ties that render context to the component render context, but Mobx keeps that render context separate. Therefore that means that hooks have to be created within a component render lifecycle (but can sometimes be called outside that context). Mobx-react ties the Mobx render lifecycle to the react lifecycle, triggering a react re-render when observed objects change. So Mobx-react nests the react render context within the Mobx render context.
React internally keeps tracks of hooks by the number of times and order the hook is called within a component render cycle. Mobx, on the other hand, wraps any "observable" object with a proxy that lets the Mobx context know if any of its properties were referenced during a Mobx "run context" (an autorun call, essentially). Then when a property is changed, Mobx knows what "run contexts" care about that property, and re-runs those contexts. This means that anywhere you have access to an observable object you can change a property on it and Mobx will react to it.
For react state hooks, react provides a custom setter function for a state object. React then uses calls to that setter to know when it needs to re-render a component. That setter can be used anywhere, even outside a React render, but you can only create that hook inside a render call, because otherwise react has no way to tell what component to tie that hook to. Creating a hook implicitly connects it to the current render context, and that's why hooks have to be created inside render calls: hook builders have no meaning outside a render call, because they have no way to know what component they are connected to -- but once tied to a component, then they need to be available anywhere. In fact, actions like onClick or a fetch callback don't occur within a render context, although the callback is often created within that context - the action callback happens after react finishes rendering (because javascript is single threaded, so the render function must complete before anything else happens).
Hooks comes as an alternatively to class based components, you should pick up one to your project and stick to it, don't mix it up. there are some motivation for the creation of hooks, as it's better stated at docs: hook motivation.
you can create hook functions apart, but they are meant to be consumed by components. it's something like using HOC (high order component) with class based components.
const myHook = () => {
[foo, setFoo] = useState('john')
// use effect for example if you need to run something at state updates
useEffect(() => {
// do something on foo changes
}, [foo])
return [foo, setFoo] // returning state and setState you can use them by your component
}
now you have a reusable hook and you can consume at your components:
const myComponent = (props) => {
[foo, setFoo] = myHook()
const handleFoo = () => {
// some logic
setFoo(someValue)
}
return (
<div>
<span>{foo}<span>
<button onClick={handleFoo}>click</button>
</div>
)
}
obs: you should avoid declare variables as var nowadays, pick const for most, and if it's a value variable (like number) that needs update use let.
When you are creating a hooks you must refer to the Rules of Hooks
You can only call hooks from a react functions.
Don’t call Hooks from regular JavaScript functions. Instead, you can:
✅ Call Hooks from React function components.
✅ Call Hooks from custom Hooks (learn about them on this page).
If you want to create a reusable hooks then you can create a custom hooks for your functions.
You can call as many functions inside a hooks.
For example, here I'm refactoring the request function as a hook.
export function useRequest(url, args) {
var userDispatch = useUserDispatch();
const fetcher = React.useCallback(() => {
return new Promise((resolve, reject) =>
fetch(url, args)
.then((response) => {
if (response.status === 401) {
logout();
reject();
}
resolve(response);
})
.catch(reject)
);
}, [url, args]);
return [fetcher, userDispatch];
}
and then consumes it.
function App() {
const [fetch, userDispatch] = useRequest("/url", {});
React.useEffect(() => {
fetch().then((response) => {
userDispatch({ type: "USER_REQUEST", payload: response });
});
}, []);
return <div>Hello world</div>;
}
Yes, you have to use Redux or MobX to solve this problem. You have to maintain isAuthenticated state in the global state of Redux or MobX. Then make an action that could be named like, toggleAuthState and pass is to the child component and toggle the state from there.
Also you can use functional components for this case. Class based components is not mandatory to use MobX or Redux. If you maintain a HOC as a Container then you can pass the actions and states to the child.
I am showing an example of using a container as a HOC:
// Container
import React from "react"
import * as actions from "../actions"
import ChildComponent from "../components/ChildComponent"
import { connect } from "react-redux"
import { bindActionCreators } from "redux"
const Container = props => <ChildComponent { ...props } />
const mapStateToProps = state => ({ ...state })
const mapDispatchToProps = dispatch => bindActionCreators(actions, dispatch)
export default connect(mapStateToProps, mapDispatchToProps)(Container)
Then in ChildComponent you can use your states and dispatch actions whenever you need.
I am new in Vue jS [version 2]. There are 3 component in my page. I want to use a axios get data available in all pages. I have done as follows in my app.js
const router = new VueRouter({mode: 'history', routes });
Vue.mixin({
data: function () {
return {
pocketLanguages: [],
}
},
mounted() {
var app = this;
axios.get("/get-lang")
.then(function (response) {
app.pocketLanguages = response.data.pocketLanguages;
})
}
})
const app = new Vue({
router,
}).$mount('#app');
and using this pocketLanguages in a component like
{{ pocketLanguages.login_info }} this. Its working fine but My Issue is axios.get('') triggering 4 times when page load [in console]
Now how can I trigger this only once or anything alternative suggestion will be appreciated to do this if explain with example [As I am new in Vue]
You are using a global mixin, which means that every component in your app is going to make that axios get call when it's mounted. Since your page has several components in it, no wonder the call is being made several times. What you need to do here is either:
Create a normal mixin and only use it in the master/container/page component in every route that actually needs to fetch the data by providing the option mixins: [yourMixinsName]. That component can then share the data with the other components in the page.
If your data is common between pages then it's better to use a global store such as Vuex to simplify state management.
On a side note: It is usually better to handle your data initialization in the created hook. Handling it in the mounted hook can lead to some pitfalls that include repeated calls, among other things, due to parent/child lifecycle hooks execution order. Please refer to this article for more information on the subject.
Finally problem solved
In resources/js/components/LoginComponent.vue file
<script>
import translator from '../translation';
export default {
mixins:[translator],
beforeCreate: function() {
document.body.className = 'login-list-body';
},
.....
mounted() {
this.langTrans();
}
and my translation.js file at /resources/js
export default {
data: function() {
return {
pocketLanguages: []
};
},
methods: {
langTrans: function() {
var self = this;
axios.get('/get-lang')
.then(function (response) {
self.pocketLanguages = response.data.pocketLanguages;
});
}
}
};
We have a ReactNative app that uses redux, redux-persist and a HeadlessJS task. This task needs to have access to the store. As the task fires without booting the entire app (and so has no access by default), we thought we could simply create the store inside the task as well so that it would be rehydrated by redux-persist. It turns out, however, that the store created in this way is different from the one in the app: after running, they contain different values. We tested this in several ways and it seems indeed a problem with the stores (and not with the actions for instance)
How should we access a Redux store from an HeadlessJS task?
Relevant code:
store/configure.js:
configureStore = (client) => {
const middleware = createMiddleware(client);
const finalCreateStore = applyMiddleware(thunk, middleware, logger)(createStore);
const store = finalCreateStore(rootReducer, undefined, autoRehydrate());
return store;
};
In use (both in the app and in the service):
const client = new ApiClient();
const store = configureStore(client);
client.setStore(store);
persistStore(store, {
storage: AsyncStorage,
}
In the app we simply use the Provider from react-redux to use the store, in the service we use store.dispatch.
For people looking for solution. I have found the solution in here.
The idea is to bind the store to async method.
https://github.com/react-native-kit/react-native-track-player/issues/63
Copy pasting the solution here.
// index
const store = ...
....registerHeadlessTask('TrackPlayer', () => require('event-handler.js').bind(null, store));
// event-handler.js
module.exports = async (store, data) {
if(data.type == '...') {
store.dispatch(...);
}
};
simply create the store inside the task as well so that it would be rehydrated by redux-persist.
This did indeed happen.
You created two stores (not advisable with redux) which were both hydrate, but not linked, as there is no such thing as linked redux stores.
Every time you run createStore, it's a new store. And every time you dispatch, you do that on a specific store.
Unfortunately async or multithreaded issues are not directly addressed by redux.
It would be possible though with middleware and / or store listeners to keep the two stores in sync.
But redux is also just not a mean for communication between threads (which I assume these tasks are, or you could just give the task a reference to the store once it was created or give the main app the store reference from the task).
It's more a form of Command-Query-Separation and centralized state.
You can access your store directly as reference.
Let's say you have your headless set in index.js, then you can just simply use store there like this:
import { AppRegistry } from 'react-native';
import Store from './src/Redux/Store';
import { someAction } from './src/Redux/Actions/someActions';
import App from './App';
import { name as appName } from './app.json';
const HeadlessTask = async () => {
console.log('Receiving HeadlessTask');
const someParam = await Store.getState().Something.someParam;
if (someParam) {
Store.dispatch(someAction(someParam));
} else {
Store.dispatch(someAction());
}
};
AppRegistry.registerHeadlessTask('HeadlessTask', () => HeadlessTask);
AppRegistry.registerComponent(appName, () => App);