I have this
reducer.ts
export const userFeatureKey = 'user';
export interface UserState {
selectedUser: User | null,
users: User[],
isLoading?: boolean;
error?: any;
}
export const initialState: UserState = {
selectedUser: null,
users: [],
isLoading: false,
error: null
};
export const reducer = createReducer(
initialState,
on(loadUsers, (state) => ({...state, isLoading: true})),
on(loadUsersSuccess, (state, {data: users}) => ({...state, users, isLoading: false})),
on(loadUsersFailure, (state, error) => ({...state, error: error, isLoading: false})),
on(saveUserFailureAction, (state, error) => ({...state, isLoading: false, error: error})),
on(saveUserSuccessAction, (state, {data: user}) => ({
...state,
isLoading: false,
selectedUser: user,
users: [...state.users, user]
})
),
);
index.ts to register all reducers
import {ActionReducerMap, MetaReducer} from '#ngrx/store';
import {environment} from '../../environments/environment';
import * as fromUser from '../module/users/store/user.reducer';
export interface State {
[fromUser.userFeatureKey]: fromUser.UserState;
}
export const reducers: ActionReducerMap<State> = {
[fromUser.userFeatureKey]: fromUser.reducer
};
export const metaReducers: MetaReducer<State>[] = !environment.production ? [] : [];
app.module.ts
StoreModule.forRoot(reducers, {metaReducers}),
selector.ts
import {createSelector} from '#ngrx/store';
import {UserState} from "./user.reducer";
export const userSelector = createSelector(
(state: UserState) => state.users,
(users) => users
)
In my component user.component.ts
constructor(private store: Store<UserState>) {
this.store.dispatch(loadUsers());
}
ngOnInit(): void {
this.store.pipe(select(userSelector)).subscribe(a => {
console.log("Found " + a);
});
}
redux state
{
user: {
selectedUser: null,
users: [
{
id: 3,
email: 'john.doe#gmail.com',
username: 'john.doe',
firstName: 'fsadfad',
middleName: 'sadf',
lastName: 'werew',
accountNonExpired: false,
accountNonLocked: false,
credentialsNonExpired: false,
enabled: true,
verified: false,
description: 'fsdfas',
phone: '0716650714',
lastLogin: null,
fullName: 'Fsadfad sadf werew'
},
{
id: 21,
email: 'erwer',
username: 'sdfsd',
firstName: 'rewrew',
middleName: 'sadfa',
lastName: 'sdfsa',
accountNonExpired: false,
accountNonLocked: false,
credentialsNonExpired: false,
enabled: true,
verified: false,
description: 'sdfds',
phone: 'werw',
lastLogin: null,
fullName: 'Rewrew sadfa sdfsa'
}
],
isLoading: false,
error: null
}
}
But I get no data from the selector. Can someone help?
Solved the problem. the problem was i needed to create feature selector first
export const selectUserFeature = createFeatureSelector<UserState>(userFeatureKey);
Then my selector.ts becomes
import {createFeatureSelector, createSelector} from '#ngrx/store';
import {userFeatureKey, UserState} from "./user.reducer";
export const selectUserFeature = createFeatureSelector<UserState>(userFeatureKey);
export const userSelector = createSelector(
selectUserFeature,
(state) => state.users
)
export const userIsLoadingSelector = createSelector(
selectUserFeature,
(isLoading) => isLoading
)
Related
this is my InputType in schema.graphql:
input RegisterInput {
birthday: String!
email: String!
firstName: String!
gender: String!
interests: [String!]!
lastName: String!
password: String!
}
and this is my mutation:
const RegisterInput = inputObjectType({
name: 'RegisterInput',
definition(t) {
t.string('birthday', { nullable: false });
t.string('email', { nullable: false });
t.string('firstName', { nullable: false });
t.string('lastName', { nullable: false });
t.string('gender', { nullable: false });
t.string('password', { nullable: false });
t.list.field('interests', {
type: 'String',
nullable: false,
});
},
});
const Mutation = objectType({
name: 'Mutation',
definition(t) {
t.field('register', {
type: User,
args: {
data: arg({ type: RegisterInput }),
},
resolve: async (
_root,
{ data: { password, interests, ...userData } },
{ prisma }
) => {
const hashedPassword = await bcrypt.hash(password, 10);
const user = await prisma.user.create({
data: {
...userData,
interests: [...interests],
password: hashedPassword,
},
});
return user;
},
});
my interests is just an array of strings, .e.g: ['abcd', 'def']
but i got this error:
Unknown arg `0` in data.interests.0 for type UserCreateInterestInput. Available args:
type UserCreateInterestsInput {
set?: List<String>
}
that error will repeat depending of how many items is in the array, e.g.: Unknown arg '1' and so on, same error message, how do i fix this?
You must provide a list of strings to set argument, such as:
type UserCreateInterestsInput {
set?: List<String>
}
Refer to this issue for more information.
const Mutation = objectType({
name: 'Mutation',
definition(t) {
t.field('register', {
type: User,
args: {
data: arg({ type: RegisterInput }),
},
resolve: async (
_root,
{ data: { password, interests, ...userData } },
{ prisma }
) => {
const hashedPassword = await bcrypt.hash(password, 10);
const user = await prisma.user.create({
data: {
...userData,
interests: {set: interests},
password: hashedPassword,
},
});
return user;
},
});
Hope this helps
Happened to me earlier, turns out it was a query mistake.
mutation {
createFruit(data:{
name: "Banana",
images: {
set: ["image_1.img", "image_2.img"]
}
}) {
name
images
}
}
Note it's not images: ["image_1.img", "image_2.img"]
fyi with prisma you can do t.model.interest() when defining objectType
I've done this simple test
// Mocks
const loginResponseData: LoginResponseDto = {
auth: { id: 1, username: 'me', roles: [] },
token: {
token: 'abc',
expirationEpochSeconds: 12345
}
};
describe('AuthReducer', () => {
describe('loginSuccess', () => {
it('should show loginResponseData state', () => {
const createAction = loginSuccess({ payload: loginResponseData });
const result = reducer(initialState, createAction);
console.log('AUTH', result);
// How Can I test this?
//expect(result).toEqual(loginResponseData);
});
});
});
export const initialState: State = {
error: null,
loading: false,
registered: false,
payload: null
};
const authReducer = createReducer(
initialState,
on(AuthActions.loginSuccess, (state, { payload }) => {
return {
...state,
error: null,
loading: false,
payload
};
})
);
How I can test result with loginResponseData?
result of a reducer is a new state.
You need to share code of your reducer for the right answer. Or to share what console.log outputs.
Because in your question the code is correct
describe('AuthReducer', () => {
describe('loginSuccess', () => {
it('should show loginResponseData state', () => {
const actionPayload: LoginResponseDto = {
auth: { id: 1, username: 'me', roles: [] },
token: {
token: 'abc',
expirationEpochSeconds: 12345
}
};
// for the test it's fine to have an empty object
const initialState: any = {
};
// check what should be changed
const expectedState = {
payload: {
auth: { id: 1, username: 'me', roles: [] },
token: {
token: 'abc',
expirationEpochSeconds: 12345
},
},
error: null,
loading: false,
};
const createAction = loginSuccess({ payload: loginResponseData });
// returns updated state we should compare against expected one.
const actualState = reducer(initialState, createAction);
// assertions
expect(actualState).toEqual(expectedState);
});
});
});
I'm trying to create default state. And have the following setup:
export const GET_MOVIE = gql`
query movie($id: String!){
movie(id: $id){
id
title
overview
backdrop_path
runtime
vote_count
vote_average
}
}
`;
here is where I'm making a request
export const FeaturedMovie = compose(
graphql(GET_MOVIE, {
props: ({ data }) => ({ data }),
options: ownProps => ({
variables: {
id: `${ownProps.movie.id}`
},
})
})
)(FeaturedMovieView);`
const defaults = {
Movie: {
__typename: 'Movie',
Movie: 299536,
backdrop_path: '/bOGkgRGdhrBYJSLpXaxhXVstddV.jpg',
id: '299536',
overview: '',
runtime: '149',
title: '',
vote_average: 8.3,
vote_count: 7600
}
};
const client = new ApolloClient({
uri: process.env.BASE_URL,
clientState: {
defaults
}
});
There is no problem with regular queries. But default state does not work.
I'm trying to provide a mock schema to a component using React Apollo 2.1. However, it returns this error.
Error: Network error: No more mocked responses for the query: {
me {
id
email
username
first_name
last_name
bio
website
}
}
, variables: {}
at new ApolloError (ApolloError.js:43)
at ObservableQuery.currentResult (ObservableQuery.js:107)
at Query._this.getQueryResult (react-apollo.browser.umd.js:319)
at Query.render (react-apollo.browser.umd.js:421)
at finishClassComponent (react-dom.development.js:8389)
at updateClassComponent (react-dom.development.js:8357)
at beginWork (react-dom.development.js:8982)
at performUnitOfWork (react-dom.development.js:11814)
at workLoop (react-dom.development.js:11843)
at renderRoot (react-dom.development.js:11874)
How did you add mock functionality on React Apollo 2.1? I tried searching the solutions but both information for older versions and newer ones and couldn't resolve this.
Here's the code.
index.stories.js
import React from 'react';
import { storiesOf } from '#storybook/react';
import { action } from '#storybook/addon-actions';
import { makeExecutableSchema, addMockFunctionsToSchema } from 'graphql-tools';
import gql from 'graphql-tag'
import { MemoryRouter } from 'react-router';
import { MockedProvider } from 'react-apollo/test-utils';
import { buildMockedClient } from '../../../mockedApolloClient';
import AccountSettings from './index';
const typeDefs = `
interface User {
id: ID!,
email: String!,
username: String,
first_name: String,
last_name: String,
bio: String,
website: String
}
type Student implements User {
id: ID!,
email: String!,
username: String,
first_name: String,
last_name: String,
bio: String,
website: String
}
type InputError {
key: String!
message: String!
}
type UserResult {
errors: InputError,
user: User
}
input UpdateAccountInput {
first_name: String
last_name:String
email: String
username: String
bio: String
website: String
}
type Query {
me: User
}
type Mutation {
updateAccount(params: UpdateAccountInput!): UserResult!
}
`
const typeResolvers = {
User: {
__resolveType(data) {
return data.__typename // typename property must be set by your mock functions
}
}
}
const me = {
id: () => 1,
email: () => 'testuser#test.jp',
username: () => 'hiro1107',
first_name: () => 'Atsuhiro',
last_name: () => 'Teshima',
bio: () => 'test',
website: () => 'https://www.test.jp',
}
const schema = makeExecutableSchema({
typeDefs,
typeResolvers
})
const mocks = {
User: () => ({
id: () => 1,
email: () => 'testuser#codegrit.jp',
username: () => 'hiro1107',
first_name: () => 'Atsuhiro',
last_name: () => 'Teshima',
bio: () => 'test',
website: () => 'https://www.codegrit.jp',
__typename: () => 'Student'
}),
Query: () => ({
me: () => me
})
}
addMockFunctionsToSchema({
schema,
mocks,
preserveResolvers: false
});
storiesOf('Account Settings', module)
.addDecorator(story => (
<MockedProvider client={mockedClient} mocks={mocks} >
<MemoryRouter initialEntries={['/']}>{story()}</MemoryRouter>
</MockedProvider>
))
.add('With Mock', () => (
<AccountSettings />
));
const mockedClient = buildMockedClient(schema);
storiesOf('Account Settings', module)
.addDecorator(story => (
<MockedProvider client={mockedClient} mocks={mocks} >
<MemoryRouter initialEntries={['/']}>{story()}</MemoryRouter>
</MockedProvider>
))
.add('With Mock', () => (
<AccountSettings />
));
mockedApolloClient.js
import { ApolloClient } from 'apollo-client';
import { SchemaLink } from 'apollo-link-schema';
import { InMemoryCache } from 'apollo-cache-inmemory';
const apolloCache = new InMemoryCache(window.__APOLLO_STATE__);
export function buildMockedClient(schema) {
return new ApolloClient({
cache: apolloCache,
link: new SchemaLink({ schema })
})
}
package.json
"apollo-cache-inmemory": "^1.1.9",
"apollo-client": "^2.2.5",
"apollo-link-context": "^1.0.7",
"apollo-link-http": "^1.5.2",
"apollo-link-schema": "^1.1.0",
"graphql": "^0.13.1",
"graphql-tag": "^2.8.0",
"graphql-tools": "^2.24.0",
"react": "^16.3.1",
"react-apollo": "^2.1.0",
"react-dom": "^16.3.1",
I found out that I need to use ApolloProvider instead MockedProvider.
So, this code will work.
import React from 'react';
import { storiesOf } from '#storybook/react';
import { action } from '#storybook/addon-actions';
import { makeExecutableSchema, addMockFunctionsToSchema } from 'graphql-tools';
import gql from 'graphql-tag'
import { MemoryRouter } from 'react-router';
import { ApolloProvider, Query } from 'react-apollo';
import { buildMockedClient } from '../../../mockedApolloClient';
import AccountSettings from './index';
const typeDefs = `
type Query {
me: User!
}
type Mutation {
updateAccount(params: UpdateAccountInput!): UserResult!
}
interface User {
id: ID!,
email: String!,
username: String,
first_name: String,
last_name: String,
bio: String,
website: String
}
type Student implements User {
id: ID!,
email: String!,
username: String,
first_name: String,
last_name: String,
bio: String,
website: String
}
type InputError {
key: String!
message: String!
}
type UserResult {
errors: InputError,
user: User
}
input UpdateAccountInput {
first_name: String
last_name:String
email: String
username: String
bio: String
website: String
}
`
const typeResolvers = {
User: {
__resolveType(data) {
return data.__typename()
}
}
}
const mocks = {
User: () => ({
id: () => 1,
email: 'testuser#codegrit.jp',
username: 'hiro1107',
first_name: 'Atsuhiro',
last_name: 'Teshima',
bio: 'test',
website: 'https://www.test.jp',
__typename: 'Student',
}),
Student: () => ({
id: () => 1,
email: 'testuser#test.jp',
username: 'hiro1107',
first_name: 'Atsuhiro',
last_name: 'Teshima',
bio: 'test',
website: 'https://www.test.jp',
__typename: () => 'Student'
}),
query: () => ({
me: () => ({
id: () => 1,
email: 'testuser#test.jp',
username: 'hiro1107',
first_name: 'Atsuhiro',
last_name: 'Teshima',
bio: 'test',
website: 'https://www.test.jp',
__typename: () => 'Student'
})
})
}
const schema = makeExecutableSchema({
typeDefs,
resolvers: typeResolvers
})
addMockFunctionsToSchema({
schema,
mocks,
preserveResolvers: true
});
const client = buildMockedClient(schema);
const userQuery = gql`
query {
me {
id
email
username
first_name
last_name
bio
website
}
}
`
storiesOf('Account Settings', module)
.addDecorator(story => (
<ApolloProvider client={client} >
<MemoryRouter initialEntries={['/']}>{story()}</MemoryRouter>
</ApolloProvider>
))
.add('With Mock', () => (
<AccountSettings />
));
Please check my code below i have to navigate to EmployeeCreate after login success .I use this in dispatch(NavigationActions.navigate({ routeName: 'EmployeeCreate' })); in my AuthActions.js. but not working.Previously i used 'react-native-router-flux' instead of react-navigation. Iam new to react-native and couldn't find the issue.
App.js
import React, { Component } from 'react';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import firebase from 'firebase';
import ReduxThunk from 'redux-thunk';
import reducers from './reducers';
import Router from './Router';
class App extends Component {
componentWillMount() {
const config = {
apiKey: "###",
authDomain: "###",
databaseURL: "###",
projectId: "###",
storageBucket: "###,
messagingSenderId: "0000000"
};
firebase.initializeApp(config);
}
render() {
const store = createStore(reducers, {}, applyMiddleware(ReduxThunk));
return (
<Provider store={store}>
<Router />
</Provider>
);
}
}
export default App;
Router.js
import React from 'react';
import { StackNavigator} from 'react-navigation';
import LoginForm from './components/LoginForm';
import EmployeeList from './components/EmployeeList';
import EmployeeCreate from './components/EmployeeCreate';
import EmployeeEdit from './components/EmployeeEdit';
const RouterComponent = StackNavigator({
LoginForm : {screen : LoginForm},
EmployeeCreate : {screen :EmployeeCreate},
EmployeeEdit:{screen:EmployeeEdit},
},
{
headerMode : 'none',
navigationOptions:{
headerVisible : false,
}
}
)
export default RouterComponent;
AuthActions.js
import firebase from 'firebase';
import { NavigationActions } from 'react-navigation'
import {
EMAIL_CHANGED,
PASSWORD_CHANGED,
LOGIN_USER_SUCCESS,
LOGIN_USER_FAIL,
LOGIN_USER
} from './types';
export const emailChanged = (text) => {
return {
type: EMAIL_CHANGED,
payload: text
};
};
export const passwordChanged = (text) => {
return {
type: PASSWORD_CHANGED,
payload: text
};
};
export const loginUser = ({ email, password }) => {
return (dispatch) => {
dispatch({ type: LOGIN_USER });
firebase.auth().signInWithEmailAndPassword(email, password)
.then(user => loginUserSuccess(dispatch, user))
.catch((error) => {
console.log(error);
firebase.auth().createUserWithEmailAndPassword(email, password)
.then(user => loginUserSuccess(dispatch, user))
.catch(() => loginUserFail(dispatch));
});
};
};
const loginUserFail = (dispatch) => {
dispatch({ type: LOGIN_USER_FAIL });
};
const loginUserSuccess = (dispatch, user) => {
dispatch({
type: LOGIN_USER_SUCCESS,
payload: user
});
dispatch(NavigationActions.navigate({ routeName: 'EmployeeCreate' }));
};
AuthReducer.js
import {
EMAIL_CHANGED,
PASSWORD_CHANGED,
LOGIN_USER_SUCCESS,
LOGIN_USER_FAIL,
LOGIN_USER
} from '../actions/types';
const INITIAL_STATE = {
email: '',
password: '',
user: null,
error: '',
loading: false
};
export default (state = INITIAL_STATE, action) => {
switch (action.type) {
case EMAIL_CHANGED:
return { ...state, email: action.payload };
case PASSWORD_CHANGED:
return { ...state, password: action.payload };
case LOGIN_USER:
return { ...state, loading: true, error: '' };
case LOGIN_USER_SUCCESS:
return { ...state, ...INITIAL_STATE, user: action.payload };
case LOGIN_USER_FAIL:
return { ...state, error: 'Authentication Failed.', password: '', loading: false };
default:
return state;
}
};
You are using dispatch method of Redux. You should be using the dispatch method of React-navigation instead. You can do one of these:
1) Do this.props.navigation.dispatch(NavigationActions.navigate({ routeName: 'EmployeeCreate' }))
2) Or integrate React-navigation with Redux ( recommended for your case especially ) and use Redux's default dispatch. I have created a barebones repo just for react-navigation + Redux
React navigation with Redux flow is changed little bit in newer versions of React Navigation.
You can checkout the best way to do it from 3.x in their documentation itself.
https://reactnavigation.org/docs/en/navigating-without-navigation-prop.html