There is such code in the VUEX repository:
export const state = () => ({
z: 'sdfjkhskldjfhjskjdhfksjdhf',
});
export const mutations = {
init_data_for_firmenistorie2 (state, uploadDbFirmenistorieData){
state.z = uploadDbFirmenistorieData;
},
};
async nuxtServerInit ({commit}) {
console.log('111');
commit('init_data_for_firmenistorie2', 123)
}
}
My question is:
How should I call to nuxtServerInit in such a way that I can use it to rewrite the value of state z?
P.S. Right now my code is not working.
If your store/index.js has an action nuxtServerInit, then Nuxt will invoke it.
So your code ends up looking like
export const state = () => ({
z: 'sdfjkhskldjfhjskjdhfksjdhf',
});
export const mutations = {
init_data_for_firmenistorie2(state, uploadDbFirmenistorieData) {
state.z = uploadDbFirmenistorieData;
},
};
export const actions = {
nuxtServerInit({ commit }) {
console.log('111');
commit('init_data_for_firmenistorie2', 123);
},
};
Well you create a actions object, and then you put your nuxtServerInit in there:
export const actions = {
nuxtServerInit(vuexContext, context){
vuexContext.commit('init_data_for_firmenistorie2', 123);
}
}
With context you can additional have access to for example params, routes, redirect etc.
The docs: https://nuxtjs.org/api/context
Related
I have data folder that contains events.ts:
export const EventsData: Event[] = [
{
name: 'School-Uniform-Distribution',
images: ['/community/conferences/react-foo.png', "/community/conferences/react-foo.png"],
},
{
name: 'College-Uniform',
images: ['/community/conferences/react-foo.png', "/community/conferences/react-foo.png"],
},
];
type Event is:
export type Event = {
name: string;
images: string[];
};
I have the getStaticPath and getStaticProps methods in pages/our-contribution/[pid].tsx :
export const getStaticProps: GetStaticProps<Props> = async (context) => {
const event = EventsData;
console.log(event, "event")
return {
props: { event: event },
};
};
export async function getStaticPaths() {
// Get the paths we want to pre-render based on posts
const paths = EventsData.map(event => ({
params: {pid: event.name},
}));
console.log(paths, "paths")
// We'll pre-render only these paths at build time.
return {paths, fallback: false}
}
I get this error:
Can you help me, please ?
Update:
This is the error trace for one route:
pages/our-contribution/[pid].tsx:
import { useRouter } from 'next/router';
import { GetStaticProps } from 'next';
import { Event } from 'types/event';
import {EventsData} from 'data/events';
type Props = {
event: Event[];
};
const Event = ({event} : Props) => {
const router = useRouter()
const { pid } = router.query
return <p>Event: {event}</p>
}
export const getStaticProps: GetStaticProps<Props> = async (context) => {
const event = EventsData;
console.log(event, "event")
return {
props: { event: event },
};
};
export async function getStaticPaths() {
// Get the paths we want to pre-render based on posts
const paths = EventsData.map(event => ({
params: {pid: event.name},
}));
console.log(paths, "paths")
// We'll pre-render only these paths at build time.
return {paths, fallback: false}
}
export default Event
I think there are a couple of errors in the code.
One error that block your build is
const Event = ({event} : Props) => {
const router = useRouter()
const { pid } = router.query
return <p>Event: {event}</p>
}
You can't directly print an object or array in tsx, you should convert the object first into string if you are trying to debug it. Something like:
return <p>Event: {event.toString()}</p>
Then a i notice something strange in your variables name event props looks like a single event but instead you give an array of events i don't know if it is correct but maybe it should be like this:
type Props = {
event: Event;
};
or it should be named:
type Props = {
events: Event[];
};
Hi I'm very new to React and this is my first project, what I'm trying to do is when onClick, the code will fetch data from API using Axios and display the object.
First, I tried using a reducer and failed. Read on Redux docs, that the way to resolve when dealing with asynchronous actions we to use applymiddleware. So after trying and adjusting I end up with:
// I KNOW... YOU MIGHT BE THINKING WHY REDUX FOR SUCH A SIMPLE APP, WHY NOT JUST USE REACT?? IT'S SUCH AN OVER-KILL. WELL... I FORCE MYSELF TO IMPLEMENT IT ON THE FIRST PROJECT TO UNDERSTAND AND DEMONSTRATE THE FUNCTIONALITY OF REACT, REDUX AND REACT-REDUX. SIMPLE APP IS IT CLEARER/OBVIOUS.
const thunk = ReduxThunk.default;
const { Provider, connect } = ReactRedux;
const { createStore, applyMiddleware } = Redux;
const GENERATE = 'GENERATE';
class QuoteGenerator extends React.Component {
generateQuote = () => {
this.props.dispatch(generateNewQuote());
};
generate = () => {
this.props.dispatch({
type: GENERATE,
});
};
render() {
console.log(this.props);
return (
<div>
<h1>{this.props.quote}</h1>
<button onClick={this.generate}>Generate</button>
</div>
);
}
}
const mapStateToProps = (state) => ({
quote: state.quote,
});
const Container = connect(mapStateToProps)(QuoteGenerator);
/**************************************************************/
const initState = {
quote: 'Generate Me!',
};
function fetchQuote() {
return axios.get(
'https://gist.githubusercontent.com/camperbot/5a022b72e96c4c9585c32bf6a75f62d9/raw/e3c6895ce42069f0ee7e991229064f167fe8ccdc/quotes.json'
);
}
function returnQuote(quote) {
return {
quote: quote,
};
}
// But what do you do when you need to start an asynchronous action,
// such as an API call, or a router transition?
// Meet thunks.
// A thunk is a function that returns a function.
// This is a thunk.
function generateNewQuote(state = initState, action) {
// if (action.type === GENERATE) {
// console.log("It Works")
// Invert control!
// Return a function that accepts `dispatch` so we can dispatch later.
// Thunk middleware knows how to turn thunk async actions into actions.
return function (dispatch) {
return fetchQuote().then((res) => {
const selectRandomQuote = Math.floor(
Math.random() * res.data.quotes.length
);
const quoteObj = {
quote: res.data.quotes[selectRandomQuote]['quote'],
author: res.data.quotes[selectRandomQuote]['author'],
};
console.log({ quote: res.data.quotes[selectRandomQuote]['quote'] });
return { quote: res.data.quotes[selectRandomQuote]['quote'] };
});
};
// } else {
// return state;
// }
}
function reducer(state = initState, action) {
if (action.type === GENERATE) {
return {
quote: 'It Works!',
};
} else {
return state;
}
}
// applyMiddleware supercharges createStore with middleware:
const store = createStore(generateNewQuote, applyMiddleware(thunk));
class App extends React.Component {
render() {
return (
<Provider store={store}>
<Container />
</Provider>
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
I'm able to trigger the function and console log the output but with no luck, it's not showing...
I really appreciate the guidance to share some light on this, been really keen on React but the first has hit me hard. Thanks in advance, cheers!
I'm trying to figure out how to deal with stale event handlers returned by a hook. First when the component is first rendered, it makes a an asynchronous request to api to fetch credentials. Then these credentials are used when pressing a submit button in a dialog to create a resource. The problem is the credentials for the dialog submit button click event handler are undefined even after the credentials have been fetched.
credentials.js
import { useEffect } from 'react';
import { api } from './api';
export const useCredentials = (setCredentials) => {
useEffect(() => {
const asyncGetCredentials = async () => {
const result = await api.getCredentials();
if (result) {
setCredentials(result);
}
};
asyncGetCredentials().then();
}, []);
return credentials;
}
useComponent.js
import { useEffect, useRef, useCallback, useState } from 'react';
import { useCredentials } from './credentials';
import { createResource } from './resources';
import { useDialog } from './useDialog';
export const useComponent = () => {
const { closeDialog } = useDialog();
const [credentials, setCredentials] = useState();
useCredentials(setCredentials);
const credentialsRef = useRef(credentials);
useEffect(() => {
// logs credentials properly after they have been fetched
console.log(credentials)
credentialsRef.current = credentials;
}, [credentials]);
const createResourceUsingCredentials = useCallback(
async function () {
// credentials and credentialsRef.current are both undefined
// even when the function is called after the credentials
// have already been fetched.
console.log(credentials);
console.log(credentialsRef.current);
createResource(credentialsRef.current);
}, [credentials, credentialsRef, credentialsRef.current]
);
const onDialogSubmit = useCallback(
async function () {
await createResourceUsingCredentials();
closeDialog();
}, [
credentials,
credentialsRef,
credentialsRef.current,
createResourceUsingCredentials,
],
);
return {
onDialogSubmit,
}
}
Try this way
export const useCredentials = (setCredentials) => {
useEffect(() => {
const asyncGetCredentials = async () => {
const result = await api.getCredentials();
if (result) {
setCredentials(result);
}
};
asyncGetCredentials().then();
}, []);
}
export const useComponent = () => {
const { closeDialog } = useDialog();
const [credentials, setCredentials] = useState(); // new add
useCredentials(setCredentials);
....
}
Why are you adding complexity, always return function and check inside the function for credentials
export const useComponent = () => {
const { closeDialog } = useDialog();
const credentials = useCredentials();
// correctly logs undefined at first and updated credentials
// when they are asynchronously received from the api.
console.log(credentials);
async function createResourceUsingCredentials() {
createResource(credentials);
}
let onClickDialogSubmit = async () => {
if (credentials) {
await createResourceUsingCredentials();
closeDialog();
}
};
return {
onClickDialogSubmit,
}
}
I found the problem was in the useCredentials hook implementation. It blocks any further requests for credentials to the api if a request is already in flight. Due to poor implementation of this functionality, if more than 1 component using that hook was rendered, only the component that was rendered first got updated credentials. I changed the useCredentials hooks so that it subscribes to the global state (that has the credentials) so that no matter which component starts the request, all components will get the credentials when the request finishes. https://simbathesailor007.medium.com/debug-your-reactjs-hooks-with-ease-159691843c3a helped a lot with debugging this issue.
I am migrating my component from a class component to a functional component using hooks. I need to access the states with useSelector by triggering an action when the state mounts. Below is what I have thus far. What am I doing wrong? Also when I log users to the console I get the whole initial state ie { isUpdated: false, users: {}}; instead of just users
reducers.js
const initialState = {
isUpdated: false,
users: {},
};
const generateUsersObject = array => array.reduce((obj, item) => {
const { id } = item;
obj[id] = item;
return obj;
}, {});
export default (state = { ...initialState }, action) => {
switch (action.type) {
case UPDATE_USERS_LIST: {
return {
...state,
users: generateUsersObject(dataSource),
};
}
//...
default:
return state;
}
};
action.js
export const updateUsersList = () => ({
type: UPDATE_USERS_LIST,
});
the component hooks I am using
const users = useSelector(state => state.users);
const isUpdated = useSelector(state => state.isUpdated);
const dispatch = useDispatch();
useEffect(() => {
const { updateUsersList } = actions;
dispatch(updateUsersList());
}, []);
first, it will be easier to help if the index/store etc will be copied as well. (did u used thunk?)
second, your action miss "dispatch" magic word -
export const updateUsersList = () =>
return (dispatch, getState) => dispatch({
type: UPDATE_USERS_LIST
});
it is highly suggested to wrap this code with { try } syntax and be able to catch an error if happened
third, and it might help with the console.log(users) error -
there is no need in { ... } at the reducer,
state = intialState
should be enough. this line it is just for the first run of the store.
and I don't understand where { dataSource } comes from.
I cannot figure out why this is not working:
-spec.js
it.only('passes props to children', () => {
const state = {
company: {
name: 'Company A'
}
},
store = fakeStore(state),
container = <HomePageContainer store={store} />;
const homePageContainer = shallow(container),
homePage = homePageContainer.find(HomePage);
expect(homePage.props.company.name).to.equal(state.company.name)
});
const fakeStore = state => {
return {
default: () => {},
subscribe: () => {},
dispatch: () => {},
getState: () => { return { state };
},
};
};
HomePageContainer.js
import React from 'react';
import { connect } from 'react-redux'
import HomePage from '../../client/components/HomePage';
export const mapStateToProps = state => {
company: state.company
}
export { HomePage }
export default connect(mapStateToProps)(HomePage);
HomePage.js
import React, { Component, PropTypes } from 'react';
export default class HomePage extends Component {
render(){
return (
<div className='homepage'>
{/*{this.props.company.name}*/}
</div>
)
}
}
I'm getting this type error because props.company is undefined so for some reason it's not persisting state to :
TypeError: Cannot read property 'name' of undefined
That error is relating to the assert when it's trying to read expect(homePage.props.company.name)
I notice that when putting a breakpoint inside mapStateToProps, that it's not picking up the state object from the store still for some reason:
I know you can pass just the store via props...and if there's nothing in the context, connect() will be able to find it via the store prop. For example in another test suite, this passes just fine:
it('shallow render container and dive into child', () => {
const container = shallow(<ExampleContainer store={fakeStore({})}/>);
expect(container.find(Example).dive().text()).to.equal('Andy');
});
Problem
At this line you pass the store as a prop into <HomePageContainer>:
// ...
container = <HomePageContainer store={store} />;
// ...
But connect() needs the store via context.
And you must wrap the object you want to return in mapStateToProps in parenthese.
Solution
You can use shallow() to make the store available as a context property.
it.only('passes props to children', () => {
const state = {
company: {
name: 'Company A'
}
};
const store = fakeStore(state);
const homePageContainer = shallow(
<HomePageContainer />,
// Make the store available via context
{ context: { store } }
);
const homePage = homePageContainer.find(HomePage);
expect(homePage.props().company.name).to.equal(state.company.name)
});
Updated mapStateToProps:
export const mapStateToProps = state => ({
company: state.company
});
Found out the problem was really my helper.
This was passing a object with property "state" in it. Not what I want. That would have meant that mapStateToProps would have had to reference the props with state.state.somePropName
const fakeStore = (state) => {
return {
default: () => {},
subscribe: () => {},
dispatch: () => {},
getState: () => { return { state };
},
};
};
changed it to this, and now mapStateToProps is working fine, it's able to access it with the props as the root level of the object literal, the object I passed in from my test:
const fakeStore = (state) => ({
default: () => {},
subscribe: () => {},
dispatch: () => {},
getState: () => ({ ...state })
});