I have a login form and where the inputs (email & password) are bound. On clicking the button to submit the form, it prevents the default behaviour and uses the login method defined in the Login.vue; Scripts.
While consoling in Login.vue; Scripts; login method, the form data printed out the {email: 'email', password: 'password'} object (desired). Once it is passed to the action (await this.signIn(this.form)), it consoled out a Vue component all of the sudden. I don't understand why this happened and how can this be solved?
Login.vue Component
Form
<form #submit.prevent="login" method="POST">
<input
type="text"
v-model="form.email"
/>
<input
type="password"
v-model="form.password"
/>
<button class="btn btn-primary">Login</button>
</form>
Scripts
<script>
import { mapActions } from 'vuex'
export default {
data() {
return {
form: {
email: '',
password: '',
},
}
},
computed: {
...mapActions('auth', ['signIn']),
},
methods: {
async login() {
/***************************************
* *
* Print out the form data object *
* *
****************************************/
console.log(this.form)
await this.signIn(this.form)
},
},
}
</script>
Vuex - Auth Module
export const actions = {
signIn({ dispatch, commit }, form) {
/***************************************************************
* *
* Print out a Vue component instead of the passed object *
* *
****************************************************************/
console.log(form)
Auth.signInWithEmailAndPassword(form.email, form.password)
.then(user => {
commit('SET_AUTHENTICATED', true)
commit('SET_USER', user.user)
this.$router.push('/')
})
.catch(err => {
console.log(err)
})
},
}
Console logged content
VueComponent {_uid: 4, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: VueComponent, …}
$attrs: (...)
$children: []
$createElement: ƒ (a, b, c, d)
$el: div
$listeners: (...)
$options: {parent: VueComponent, _parentVnode: VNode, propsData: undefined, _parentListeners: undefined, _renderChildren: undefined, …}
$parent: VueComponent {_uid: 3, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: VueComponent, …}
$refs: {}
$root: Vue {_uid: 2, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: Vue, …}
$scopedSlots: {$stable: true, $key: undefined, $hasNormal: false}
$slots: {}
$store: Store {_committing: false, _actions: {…}, _actionSubscribers: Array(1), _mutations: {…}, _wrappedGetters: {…}, …}
$vnode: VNode {tag: "vue-component-4", data: {…}, children: undefined, text: undefined, elm: div, …}
form: (...)
login: ƒ ()
signIn: (...)
__VUE_DEVTOOLS_UID__: "1:4"
_c: ƒ (a, b, c, d)
_computedWatchers: {signIn: Watcher}
_data: {__ob__: Observer}
_directInactive: false
_events: {hook:beforeDestroy: Array(1)}
_hasHookEvent: true
_inactive: null
_isBeingDestroyed: false
_isDestroyed: false
_isMounted: true
_isVue: true
_renderProxy: Proxy {_uid: 4, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: VueComponent, …}
_routerRoot: Vue {_uid: 2, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: Vue, …}
_self: VueComponent {_uid: 4, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: VueComponent, …}
_staticTrees: null
_uid: 4
_vnode: VNode {tag: "div", data: undefined, children: Array(2), text: undefined, elm: div, …}
_watcher: Watcher {vm: VueComponent, deep: false, user: false, lazy: false, sync: false, …}
_watchers: (2) [Watcher, Watcher]
$data: (...)
$isServer: (...)
$props: (...)
$route: (...)
$router: (...)
$ssrContext: (...)
get $attrs: ƒ reactiveGetter()
set $attrs: ƒ reactiveSetter(newVal)
get $listeners: ƒ reactiveGetter()
set $listeners: ƒ reactiveSetter(newVal)
get form: ƒ proxyGetter()
set form: ƒ proxySetter(val)
__proto__: Vue
As Sumurai8 mentioned, I only need to put the ...mapActions('auth', ['signIn']) in methods and not in computed.
methods: {
...mapActions('auth', ['signIn']),
async login() {
console.log(this.form)
await this.signIn(this.form)
},
},
Related
I'm trying to develop a chrome extension that access the conversation of WhatsApp Web. I'm struggling to access the Conversation component state (component that I can see with the React developper tools)
When I try
document.querySelector("#main")['__reactFiber$lwbvlqgcvdi']
I get something like this
alternate: zu {tag: 5, key: null, elementType: 'div', type: 'div', stateNode: div#main._1fqrG, …}
child: zu {tag: 0, key: '33619488273-1490436851#g.us', stateNode: null, elementType: ƒ, type: ƒ, …}
childLanes: 1
dependencies: null
elementType: "div"
firstEffect: zu {tag: 5, key: null, elementType: 'div', type: 'div', stateNode: div._26lC3, …}
flags: 0
index: 0
key: null
lanes: 0
lastEffect: zu {tag: 1, key: null, stateNode: t, elementType: ƒ, type: ƒ, …}
memoizedProps: {id: 'main', className: '_1fqrG', style: {…}, children: {…}}
memoizedState: null
mode: 0
nextEffect: null
pendingProps: {id: 'main', className: '_1fqrG', style: {…}, children: {…}}
ref: e=> {…}
return: zu {tag: 10, key: null, elementType: {…}, type: {…}, stateNode: null, …}
sibling: zu {tag: 5, key: null, elementType: 'div', type: 'div', stateNode: div, …}
stateNode: div#main._1fqrG
tag: 5
type: "div"
updateQueue: null
[[Prototype]]: Object
instead of the following result I get when using the React developer tools $r variable
context: {}
props: {setInterval: ƒ, clearInterval: ƒ, setTimeout: ƒ, clearTimeout: ƒ, requestAnimationFrame: ƒ, …}
refs: {}
state: {chat: g, msgCollection: u, focusCtx: {…}, showConversationPreview: false, animate: false, …}
updater: {isMounted: ƒ, enqueueSetState: ƒ, enqueueReplaceState: ƒ, enqueueForceUpdate: ƒ}
_handleCloseChat: e=> {…}
_handleOpenChat: (e,t,a)=> {…}
_handleOpenChatId: 1
_msgCollectionChanged: (e,t,a,s)=> {…}
_newChatScrollInfo: (e,t)=> {…}
_openedChatInfo: {chat: g, renderedMsgsInfo: {…}, visibleMsgOrder: Array(11), clientHeight: 572}
_reactInternals: zu {tag: 1, key: null, stateNode: y, elementType: ƒ, type: ƒ, …}
_refContainer: {current: t.default}
_windowGainedFocus: ()=> {…}
_windowLostFocus: ()=> {…}
[[Prototype]]: m
document.querySelector("#main")['__reactFiber$lwbvlqgcvdi'].stateNodereturns the same element than document.querySelector("#main")['__reactFiber$lwbvlqgcvdi']
document.querySelector("#main")['__reactFiber$lwbvlqgcvdi'].return gives me the context provider wrapping the component
return.stateNode returns null
What do I miss?
I finally figured it out.
It was the great great great great grandparent of the #main element. (Element react developer tools gives me as the matching DOM element for the Conversation component)
Now I know that React developer tools can give the same matching DOM element for different components ^^'
Update
To access the state I was looking for I used the following code :
document.querySelector("#main")['__reactFiber$lwbvlqgcvdi'].return.return.return.return.return.return.stateNode.state
I really found this out of luck as I was crawling up the graph of object out of boredom / despaire / curiosity ^^'
so I'm using vue-meta library to add meta tag to my vue project, and now I'm trying to add my meta from API response, this is what i got from API if i did console.log('response.data.data')
0:
meta_tags_content: "my content"
meta_tags_id: 3
meta_tags_properties: "my property"
__ob__: Observer {value: {…}, dep: Dep, vmCount: 0}
get meta_tags_content: ƒ reactiveGetter()
set meta_tags_content: ƒ reactiveSetter(newVal)
get meta_tags_id: ƒ reactiveGetter()
set meta_tags_id: ƒ reactiveSetter(newVal)
get meta_tags_properties: ƒ reactiveGetter()
set meta_tags_properties: ƒ reactiveSetter(newVal)
__proto__: Object
1:
meta_tags_content: "content"
meta_tags_id: 4
meta_tags_properties: "title"
__ob__: Observer {value: {…}, dep: Dep, vmCount: 0}
get meta_tags_content: ƒ reactiveGetter()
set meta_tags_content: ƒ reactiveSetter(newVal)
get meta_tags_id: ƒ reactiveGetter()
set meta_tags_id: ƒ reactiveSetter(newVal)
get meta_tags_properties: ƒ reactiveGetter()
set meta_tags_properties: ƒ reactiveSetter(newVal)
__proto__: Object
length: 2
I'm trying to add the meta_tags_content and meta_tags_properties to my vue meta tag function (https://www.npmjs.com/package/vue-meta), this is my meta tag function
export default {
name: 'App',
metaInfo () {
return {
title: 'Tiarapot',
meta: [
{
name: 'description',
content: 'Memang canggih (harus ganti)'
},
{
property: 'og:title',
content: 'Website Tiarapot (harus ganti)'
},
{
property: 'og:site-name',
content: 'Tiarapot'
},
{
property: 'og:type',
content: 'website'
},
{
name: 'robots',
content: 'index,follow'
}
]
}
},
}
and what I'm trying to do is to make it like this
export default {
name: 'App',
metaInfo () {
return {
title: 'Tiarapot',
meta: arrayOfConvertedresponse
}
},
}
how to convert those response of array to a meta structured object ?
expected result if i console.log(arrayOfConvertedresponse) is
[
{
property: "my properties",
content: "my content"
},
{
property: "title",
content: "content"
}
]
If you want to use responsive data in metaInfo, you'll need to assign the array to a data property and refer to it in the metaInfo function
export default {
name: 'App',
data: () => ({
arrayOfConvertedresponse: [] // define initial properties
}),
metaInfo () {
return {
title: 'Tiarapot',
meta: this.arrayOfConvertedresponse
}
},
async created () {
// load data from the API
const response = await axios.get("/api/meta-tags")
// map response to the appropriate format and assign to your data property
this.arrayOfConvertedresponse = response.data.data.map(meta => ({
property: meta.meta_tags_properties,
content: meta.meta_tags_content
}))
}
}
See https://vue-meta.nuxtjs.org/faq/async-action.html
I have an object reference from a react component (specifically swiperjs.com react component). I would like to react to changes in the objects properties (https://swiperjs.com/api/#methods), but useEffect() I find does not work in this case, with it being a reference only. Can anyone suggest what to do here?
const [mySwiper, setmySwiper] = useState(0);
useEffect(() => {
console.log(mySwiper.isEnd)
}, [mySwiper]);
Here is the setmySwiper logic, this is a
<Swiper>
...(other parameters)
onSwiper={(swiper) => setmySwiper(swiper)}
</Swiper>
And this is a console.log of mySwiper, it only appears on page refresh despite properties changing during component use:
Swiper {support: {…}, device: {…}, browser: {…}, eventsListeners: {…}, eventsAnyListeners: Array(0), …}
$: ƒ $(selector, context)
$el: Dom7 [div.swiper-container.swiper-container-initialized.swiper-container-vertical, __proto__: (...)]
$wrapperEl: Dom7 [div.swiper-wrapper, __proto__: (...)]
activeIndex: 0
allowClick: true
allowSlideNext: true
allowSlidePrev: true
allowTouchMove: true
animating: false
browser: {isEdge: false, isSafari: false, isWebView: false}
classNames: (2) ["swiper-container-initialized", "swiper-container-vertical"]
device: {ios: false, android: false}
el: div.swiper-container.swiper-container-initialized.swiper-container-vertical
eventsAnyListeners: []
eventsListeners: {_containerClasses: Array(1), _swiper: Array(1), init: Array(2), destroy: Array(2), resize: Array(1), …}
height: 535
imagesLoaded: 4
imagesToLoad: Dom7(4) [img, img, img, img, __proto__: (...)]
initialized: true
isBeginning: true
isEnd: false
isHorizontal: ƒ isHorizontal()
isVertical: ƒ isVertical()
loopCreate: ƒ ()
loopDestroy: ƒ ()
observer: {observers: Array(0), attach: ƒ, init: ƒ, destroy: ƒ}
onClick: ƒ ()
onTouchEnd: ƒ ()
onTouchMove: ƒ ()
onTouchStart: ƒ ()
originalParams: {init: true, direction: "vertical", touchEventsTarget: "container", initialSlide: 0, speed: 320, …}
params: {init: true, direction: "vertical", touchEventsTarget: "container", initialSlide: 0, speed: 320, …}
passedParams: {_emitClasses: false, on: {…}, init: true, direction: "vertical", touchEventsTarget: "container", …}
previousTranslate: 0
progress: -0
realIndex: 0
resize: {resizeHandler: ƒ, orientationChangeHandler: ƒ}
rtl: false
rtlTranslate: false
size: 535
slides: Dom7(4) [div.swiper-slide.swiper-slide-active, div.swiper-slide.swiper-slide-next, div.swiper-slide, div.swiper-slide, __proto__: (...)]
slidesGrid: (4) [0, 535, 1070, 1605]
slidesSizesGrid: (4) [535, 535, 535, 535]
snapGrid: (4) [0, 535, 1070, 1605]
snapIndex: 0
support: {touch: false, pointerEvents: true, observer: true, passiveListener: true, gestures: false}
touchEvents: {start: "pointerdown", move: "pointermove", end: "pointerup"}
touchEventsData: {isTouched: undefined, isMoved: undefined, allowTouchCallbacks: undefined, touchStartTime: undefined, isScrolling: undefined, …}
touchEventsDesktop: {start: "pointerdown", move: "pointermove", end: "pointerup"}
touchEventsTouch: {start: "touchstart", move: "touchmove", end: "touchend", cancel: "touchcancel"}
touches: {startX: 0, startY: 0, currentX: 0, currentY: 0, diff: 0}
translate: -0
velocity: 0
virtualSize: 2140
width: 1903
wrapperEl: div.swiper-wrapper
wrongRTL: false
__proto__: Object
In class based components this is relatively straightforward - you would use componentDidUpdate to get a copy of the previous state and compare it with the new one manually. Functional components do away with the idea of lifecycle methods which can often get bloated and complicated, and instead ask that you tie specific data points together with a specific useEffect to achieve specific things.
You can target the individual properties of mySwiper in different useEffect instances, and those effects will only trigger when the indiviual properties change. For instance, this will only be triggered with changes to the isEnd property:
useEffect(() => {
console.log(mySwiper.isEnd);
}, [mySwiper.isEnd]);
However, if you really want to analyse the entire object in one go, you can use a ref to store the previous value of the state and compare against that. You'll have to check it exists for the first effect pass because refs always initialise as undefined. The bottom line is that if you want to take this approach, you are going to have to do your own object comparison - React isn't going to take care of it for you:
const [mySwiper, setMySwiper] = useState(0);
const prevSwiper = useRef(mySwiper);
useEffect(() => {
if(prevSwiper.current) {
// compare prevSwiper to mySwiper
};
prevSwiper.current = mySwiper;
}, [mySwiper]);
useRef as this.ref = ... doesn’t notify you when its content changes, if you are using hooks you could change your useRef to a useCallback and that would notify you. If that doesn't work for you try using useLayoutEffect
this my code
const fallbackLng = ["en"];
const availableLanguages = ["en", "ru"];
i18n
.use(Backend)
.use(LanguageDetector)
.use(initReactI18next)
.init({
fallbackLng,
debug: true,
whitelist: availableLanguages,
interpolation: {
escapeValue: false
}
});
I see strange lines in the console
i18next::backendConnector: loaded namespace translation for language en {Form: {…}, SignUp: {…}, SignIn: {…}}
i18next::backendConnector: loaded namespace translation for language ru {Form: {…}, SignUp: {…}, SignIn: {…}}
i18next: languageChanged ru
i18next: initialized {debug: true, initImmediate: true, ns: Array(1), defaultNS: Array(1), fallbackLng: Array(1), …}
all code can be seen here codesandbox
Set debug to false in that object
{
fallbackLng,
debug: false,
whitelist: availableLanguages,
interpolation: {
escapeValue: false
}
}
We got a ReactJS frontend delivered for our school project. We have to make a Laravel backend for it. I'm using an API to fetch the dashboard layout from the database. The current frontend makes use of this variable:
const originalLayouts = getFromLS("layouts") || [];
To set the state from the local storage with this function:
function getFromLS(key) {
let ls = {};
if (global.localStorage) {
try {
ls = JSON.parse(global.localStorage.getItem("rgl-8")) || {};
} catch (e) {
/*Ignore*/
}
}
return ls[key];
}
Where the states are set:
this.state = {
items: originalLayouts.map(function(i, key, list) {
return {
i: originalLayouts[key].i,
x: originalLayouts[key].x,
y: originalLayouts[key].y,
w: originalLayouts[key].w,
h: originalLayouts[key].h,
widget: originalLayouts[key].widget,
minW: originalLayouts[key].minW,
minH: originalLayouts[key].minH,
maxH: originalLayouts[key].maxH
};
}),
selectedOption: '',
newCounter: originalLayouts.length
};
To fetch the data from the database and put the data into the items state I made this function:
loadData = () => {
let dashboardId = 1;
return axios
.get('api/dashboards/' + dashboardId)
.then(result => {
console.log(result);
this.setState({
originalLayouts: result.data,
selectedOption: '',
newCounter: originalLayouts.length
});
console.log(result.data);
})
.catch(error => {
console.error('error: ', error);
})
};
And I call this function in componentDidMount:
componentDidMount() {
this.loadData();
}
When I console log result it shows me this:
data: Array(2), status: 200, statusText: "OK", headers: {…}, config: {…}, …}
config: {adapter: ƒ, transformRequest: {…}, transformResponse: {…}, timeout: 0, xsrfCookieName: "XSRF-TOKEN", …}
data: (2) [{…}, {…}]
headers: {date: "Tue, 23 Oct 2018 08:18:41 +0000, Tue, 23 Oct 2018 08:18:41 GMT", host: "127.0.0.1:8000", x-powered-by: "PHP/7.2.3", x-ratelimit-remaining: "58", content-type: "application/json", …}
request: XMLHttpRequest {onreadystatechange: ƒ, readyState: 4, timeout: 0, withCredentials: false, upload: XMLHttpRequestUpload, …}
status: 200
statusText: "OK"
__proto__: Object
And when I console log result.data I get:
(2) [{…}, {…}]
0: {id: 1, dashboardId: 1, w: 2, h: 5, x: 0, …}
1: {id: 2, dashboardId: 1, w: 2, h: 1, x: 0, …}
length: 2
__proto__: Array(0)
Why is originalLayouts not set with the data from the arrays? Is this because I also have a dashboardId and id in my arrays? I also thought it could be something with setting the states because it makes use of the originalLayouts veriable. Or am I still missing something in my function? I'm not very experienced with React so any help is useful.
Update:
I changed:
this.setState({
originalLayouts: result.data,
selectedOption: '',
newCounter: originalLayouts.length
});
to:
this.setState({
items: result.data,
selectedOption: '',
newCounter: originalLayouts.length
});
This gives me this error:
Uncaught Error: ReactGridLayout: ReactGridLayout.children[0].static must be a boolean!
So that probably means I'm not setting the properties properly now.
Update 2:
In my database the properties moved and static were saved as 0 instead of false. So I changed those properties to false but I still got the same error:
ReactGridLayout: ReactGridLayout.children[0].static must be a boolean!
In your loadData(), you are setting the state of "originalLayouts" but your key in your initial state is "items". Have you tried to do this ?
this.setState({
items: result.data, // Here put items instead of originalLayouts
selectedOption: '',
newCounter: originalLayouts.length
});
Then you can call this.state.items to get your result.data