Custom routes without resources - react-admin

I would like to use React-Admin without resources defined but only with custom routes, is it possible?
<Admin title="Panel" basename="/" dashboard={Home} layout={CustomLayout} i18nProvider={i18nProvider}>
<CustomRoutes>
<Route path="/documentation" element={<>Documentation</>} />
</CustomRoutes>
</Admin>

I've tried this with "react-admin": "^4.5.2".
But i can not reach the custom route.It shows only white page.
my snippet:
const Ready = () => (
<CustomRoutes>
<Route path={'/contact'} element={<p>Contact</p>} key={'/contact'} />
</CustomRoutes>
);
const App = () => {
return (
<AdminContext
store={store}
dataProvider={dataProvider}
i18nProvider={defaultI18nProvider}
>
<AsyncResources />
</AdminContext>
);
};
const AsyncResources = () => {
const [resources, setResources] = React.useState([]);
React.useEffect(() => {
//empty ressource
setResources([]);
}, []);
return (
<AdminUI ready={Ready} layout={MyLayout}>
{resources}
</AdminUI>
);
};

Related

how to set UI component to state in background in react-native?

I am new in react-native, in my application I am generating QRCode by one library and it working but in android it is taking time to show on UI, when I set that component to hook to show on UI then it stuck for while and every thing getting non-responsive. After some time it shows and everything work well.
So how can put that setWalletQR in background so that I can show loader until it show to UI?
Here is my code where I am generating the QR in InteractionManager to show
const PozReceive = ({ onClose }: ReceiveProps) => {
const [walletQR, setWalletQR] = useState<ConentQR>(null);
const generateWalletQrCode = () => {
const interactionPromise = InteractionManager.runAfterInteractions(() => {
const qrCode = ConentQR(user?.walletAddress || '', walletImg, 50);
setWalletQR(qrCode);
});
return () => interactionPromise.cancel();
};
useEffect(() => {
if (!pouchQR) {
generatePouchQrCode();
}
}, []);
return (
<Modal
coverScreen={true}
isVisible={true}
onBackdropPress={onClose}
onBackButtonPress={onClose}
backdropColor={Colors.DARK_PURPLE}
backdropOpacity={0.7}
style={styles.modal}>
<>
<BlurView
style={styles.blurView}
blurType="dark"
blurAmount={20}
reducedTransparencyFallbackColor="white"
/>
<VStack style={[styles.modalContainer]}>
{!walletQR ? (
<Image style={styles.qrLoader} source={loaderGif} />
) : (
walletQR
)}
</VStack>
</>
</Modal>
);
};
and here is QR code generator code :-
const ContentQR = (
content: string,
logo: Image.propTypes.source,
logoSize: number,
backgroundColor: string = 'transparent',
) => {
return (
<QRCode
color={Colors.DARK_PURPLE}
content={content}
codeStyle={'dot'}
outerEyeStyle={'diamond'}
logo={logo}
logoSize={logoSize}
backgroundColor={backgroundColor}
/>
);
};
Someone please help me I getting stuck here for while.
You can introduce a variable isLoading and render the loader based on this variable instead of qr value.
const PozReceive = ({ onClose }: ReceiveProps) => {
const [walletQR, setWalletQR] = useState<ConentQR>(null);
const [isLoading, setIsLoading] = useState<Boolean>(false);
const generateWalletQrCode = () => {
setIsLoading(true)
const interactionPromise = InteractionManager.runAfterInteractions(() => {
const qrCode = ConentQR(user?.walletAddress || '', walletImg, 50);
setWalletQR(qrCode);
setIsLoading(false)
});
return () => interactionPromise.cancel();
};
....
<VStack style={[styles.modalContainer]}>
{isLoading && <Image style={styles.qrLoader} source={loaderGif} />}
{!isLoaing && walletQR && walletQR}
</VStack>

navigation.popToTop is not a function

I would like to test the navigation function in my code. On my actual navbar component, the functions works where by when I press the button, the user is directed to the home page.
Navbar.tsx
<Pressable
style={styles.leftArrow}
onPress={() => navigation.popToTop()}
testID="backButton">
<SvgIcon
id="arrow-left"
size={'21px'}
color={arrowColor()}
testID="leftArrow"
/>
</Pressable>
However, when I try to run the same function in my test case I get "navigation.popToTop is not a function". I have already tried to mocj the .popToTop function so Im not sure why this happens
Navbar.test.js
const mockedDispatch = jest.fn();
jest.mock('#react-navigation/native', () => {
const actualNav = jest.requireActual('#react-navigation/native');
return {
...actualNav,
useNavigation: () => ({
navigate: jest.fn(),
popToTop: jest.fn(),
dispatch: mockedDispatch,
}),
};
});
describe('Navbar unit tests', () => {
beforeEach(() => {
jest.clearAllMocks();
});
test('on button press, redure', async () => {
const {getByTestId} = render(
<Provider store={store}>
<NavigationContainer ref={navigationRef}>
<Navbar />
</NavigationContainer>
</Provider>,
);
fireEvent(getByTestId('backButton'), 'press');
expect(mockedDispatch).toHaveBeenCalledTimes(1);
expect(mockedDispatch).toHaveBeenCalledWith('Home');
});

(React Native && RTK Query) How to make sure the data has been returned when use conditional fetching

export function Login() {
const [skip, setSkip] = useState(true);
const { data, isFetching } = useVerifyUserQuery(userState, {
skip,
});
const LoginButton = () => (
<Button
title="Login"
onPress={() => {
setSkip((prev) => !prev);
}}
/>
);
return (
…
)
}
The requirement is to make a request when the button is pressed, and then store the returned data in a constant. Is there a good way to make sure data is returned before I store it.
Here is one of my solutions. Obviously it may cause some problems.
onPress={() => {
setSkip((prev) => !prev);
while(isFetching){}
// save data
}}
And with the code below, storeData will be called multiple times.
export function Login() {
const [skip, setSkip] = useState(true);
const { data, isFetching } = useVerifyUserQuery(userState, {
skip,
});
if (!isFetching && IsNotEmpty(data)){
storeData();
}
const LoginButton = () => (
<Button
title="Login"
onPress={() => {
setSkip((prev) => !prev);
}}
/>
);
return (
…
)
}
It looks like you just want to use the lazy version - useLazyVerifyUserQuery instead of common. It will be like:
export function Login() {
const [ verifyUser ] = useLazyVerifyUserQuery();
const handleLogin = async () => {
const data = await verifyUser(userState).unwrap();
// Probably you would want to use `storeData` somehow here?
}
const LoginButton = () => (
<Button
title="Login"
onPress={handleLogin}
/>
);
return (
...
)
}
PS: just a warning - using a nested component definition, like LoginButton inside Login - is a known antipattern that may cause significant performance issues.

React native Hooks sync UseState in 2 diferent files

I want to sync the value of a useState in 2 different files from a useHook
I have a file named useChangeScreen witch I use to set when I want to show the diferent Views:
export const useChangeScreen = () => {
...
const [homeActivo, setHomeActivo] = useState(false);
const [searchActivo, setSearchActivo] = useState(true);
const [profileActivo, setProfileActivo] = useState(false);
...
const irAHome = () => {
setHomeActivo(true);
setSearchActivo(false);
setProfileActivo(false);
};
const irASearch = () => {
setHomeActivo(false);
setSearchActivo(true);
setProfileActivo(false);
};
const irAProfile = () => {
setHomeActivo(false);
setSearchActivo(false);
setProfileActivo(true);
};
...
return {
homeActivo,
searchActivo,
profileActivo,
irAHome,
irASearch,
irAProfile
}
}
This hook is called in the navigation component:
export const Nav = () => {
const {
irAHome,
irANotifi,
irAProfile,
irASearch
} = useChangeScreen();
...
return (
...
<TouchableOpacity onPress={irAHome}>
...
<TouchableOpacity onPress={irASearch}>
...
<TouchableOpacity onPress={irAProfile}>
...
)
}
and in the screen controller I have this:
export const ScreenController =() => {
const {
homeActivo,
searchActivo,
profileActivo,
} = useChangeScreen();
...
return(
...
{homeActivo ? (
<HomeScreen />
) : searchActivo ? (
<SearchShopsScreen />
) : profileActivo ? null : null}
...
)
}
when I press the buttons in the nav I want the views in ScreenController to change from Home to Profile or Search, but when I press the buttons, the state dont change
You can lift up the state to the parent component and pass it down to it's children, use React Context API or Redux.
If you chose to lift up the state:
Then you would have a parent component that looks like this:
// ...
const Parent = () => {
const {
irAHome,
irANotifi,
irAProfile,
irASearch,
homeActivo,
searchActivo,
profileActivo
} = useChangeScreen();
return (
<>
<Nav
irAHome={irAHome}
irANotifi={irANotifi}
irAProfile={irAProfile}
irASearch={irASearch}
/>
<ScreenController
homeActivo={homeActivo}
searchActivo={searchActivo}
profileActivo={profileActivo}
/>
</>
);
};
// ...
Then use the values passed from props like that:
export const ScreenController =({ homeActivo, searchActivo, profileActivo }) => {
// ...
return (
// ...
{homeActivo ? (
<HomeScreen />
) : searchActivo ? (
<SearchShopsScreen />
) : profileActivo ? null : null}
// ...
);
};
and:
export const Nav = ({
irAHome,
irANotifi,
irAProfile,
irASearch
}) => {
// ...
return (
// ...
<TouchableOpacity onPress={irAHome} />
// ...
<TouchableOpacity onPress={irASearch} />
// ...
<TouchableOpacity onPress={irAProfile} />
// ...
)
}
Note:
You should've actually used only one state which stores the current screen and checked for the current screen using comparison operators.
Checkout these for more details:
Lifting State Up
React Context API
Get Started with Redux

How can I fire a function in headerRight using Formik?

I'm new to react-native and formik and I encountered this problem that I'm trying to build up.
How can I fire a function in headerRight using Formik? I have updateCorporation function that will do fire api, and formik will do the job to fire this function and after I press the Update button, but the results are undefined
I didn`t understand why its happening.
File_1.js
const CorporationContainer = (props) => {
const {
navigation,
} = props;
const updateCorporation = (values) => {
// do patch stuff with values
// but its undefined
};
useEffect(() => {
navigation.setParams({ updateCorporation: updateCorporation.bind() });
}, []);
return (
<Corporation
updateCorporation={updateCorporation} />
);
};
CorporationContainer.navigationOptions = ({ navigation }) => ({
headerRight: (
<EditBtn
onPress={() => navigation.state.params.updateCorporation()}
>
<EditText>Update</EditText>
</EditBtn>
),
});
export default CorporationContainer;
File_2.js
const Corporation = (props) => {
const {
updateCorporation,
} = props;
const emailField = useRef(null);
const validationSchema = yup.object().shape({
email: yup.string()
.ensure()
.email('Email must be valid')
.required('Email'),
});
return (
<Formik
initialValues={{
email,
}}
onSubmit={values => updateCorporation(values)}
validateOnBlur={false}
validateOnChange={false}
validationSchema={validationSchema}
>
{(formProps) => {
const {
errors,
setFieldValue,
values,
} = formProps;
return (
<Container>
<Input
name="email"
placeholder="Email Corporation"
textContentType="emailAddress"
keyboardType="email-address"
returnKeyType="done"
autoCapitalize="none"
autoCorrect={false}
ref={emailField}
value={values.email}
onChangeText={setFieldValue}
editable={!email}
error={errors.email}}
/>
</Container>
);
}}
</Formik>
);
};
export default Corporation;
In File_1.js I had to use withForm and remove all Formik things in File_2.js and use the props instead.
const CorporationContainer = (props) => {
const {
navigation,
handleSubmit,
errors,
setFieldValue,
values,
} = props;
useEffect(() => {
navigation.setParams({ updateCorporation: handleSubmit.bind() });
}, []);
return (
<ProfileProfessional
errors={errors}
setFieldValue={setFieldValue}
values={values}
/>
);
};
CorporationContainer.navigationOptions = ({ navigation }) => ({
headerRight: (
<EditBtn
onPress={() => navigation.state.params.updateCorporation()}
>
<EditText>Editar</EditText>
</EditBtn>
),
});
export default withFormik({
// ...
})(CorporationContainer);
Formik author here...
Haven't tried this out, and idk exactly how navigation binding works, but you want to bind Formik's submitForm() prop to the navigation and not the updateCorporation function. However, You will need to do this where you have access to Formik props/context (i.e. as a child of <Formik>).
import React from 'react'
import { connect } from 'formik'
const updateCorporation = (values) => {
// do patch stuff with values
// but its undefined
};
const BindSubmit = connect(({ formik, navigation }) => {
useEffect(() => {
navigation.setParams({ updateCorporation: submitForm.bind() });
}, []);
return null
})
// ... and then just render it somewhere under Formik
const Corporation = () => {
return (
<Formik>
<BindSubmit />
{/* ... same */}
</Formik>
)
}