I want to use normal React context with styled-components. I am aware of generic theme providers in styled-components, however, it will be much better if I will be able to do this by using React.useContext(). Do you know is it possible? I tried something like this.
useConfig
export function useConfig() {
const configCtx = useContext<ConfigContextShape | undefined>(ConfigContext)
return configCtx
}
example styled.ts
import { useConfig } from 'state'
import styled from 'styled-components'
const { background_color } = useConfig()
export const VisualSearchWrapper = styled.main`
color: black;
background-color: ${background_color};
`
I will be appreciated for any help.
One more update:
In the example this issue occurred:
Uncaught TypeError: Cannot read properties of undefined (reading 'context')
The ConfigContextProvider is below
import { createContext } from 'preact'
import { FC } from 'preact/compat'
import { useContext, useEffect, useState } from 'preact/hooks'
export interface ConfigProfile {
background_color: string
}
interface ConfigFunctions {
updateConfigState: (updatedConfig: ConfigProfile) => void
}
type ConfigContextShape = ConfigProfile & ConfigFunctions
export const ConfigContext = createContext<ConfigContextShape | undefined>(undefined)
export const ConfigContextProvider: FC = ({ children }) => {
const [localState, setLocalState] = useState<ConfigProfile>({
background_color: '',
})
function updateConfigState(updatedConfig: ConfigProfile) {
setLocalState({ ...localState, ...updatedConfig })
}
const ctxValue: ConfigContextShape = {
background_color: localState?.background_color ?? '',
updateConfigState
}
return <ConfigContext.Provider value={ctxValue}>{children}</ConfigContext.Provider>
}
export function useConfig() {
const configCtx = useContext<ConfigContextShape>(ConfigContext)
if (configCtx === undefined) {
throw new Error('useConfig must be used within a ConfigProvider')
}
return configCtx
}
Related
I have followed a YouTube tutorial to create a solana application, all my code works fine and the wallet gets connected successfull, but when I refresh the page the wallet gets disconnected and the function getWallet returns nothing (connected = false and the PublicKey is null)
here's my walletConnectionProvider:
import React, { FC, useMemo } from 'react';
import { ConnectionProvider, WalletProvider } from '#solana/wallet-adapter-react';
import { WalletAdapterNetwork } from '#solana/wallet-adapter-base';
import {
GlowWalletAdapter,
PhantomWalletAdapter,
SlopeWalletAdapter,
SolflareWalletAdapter,
SolletExtensionWalletAdapter,
SolletWalletAdapter,
TorusWalletAdapter,
} from '#solana/wallet-adapter-wallets';
import {
WalletModalProvider,
WalletDisconnectButton,
WalletMultiButton
} from '#solana/wallet-adapter-react-ui';
import { clusterApiUrl } from '#solana/web3.js';
require('#solana/wallet-adapter-react-ui/styles.css');
export const WalletConnectionProvider = ({children}) => {
const network = WalletAdapterNetwork.Devnet;
const endpoint = useMemo(() => clusterApiUrl(network), [network]);
const wallets = useMemo(
() => [
new PhantomWalletAdapter(),
new GlowWalletAdapter(),
new SlopeWalletAdapter(),
new SolflareWalletAdapter({ network }),
new TorusWalletAdapter(),
],
[network]
);
return (
<ConnectionProvider endpoint={endpoint}>
<WalletProvider wallets={wallets} autoConnect>
<WalletModalProvider>
{children}
</WalletModalProvider>
</WalletProvider>
</ConnectionProvider>
);
};
export default WalletConnectionProvider
thanks
You have to add AutoConnectProvider, create a file called AutoConnectProvider and add this code
import { useLocalStorage } from '#solana/wallet-adapter-react';
import { createContext, FC, ReactNode, useContext } from 'react';
export interface AutoConnectContextState {
autoConnect: boolean;
setAutoConnect(autoConnect: boolean): void;
}
export const AutoConnectContext = createContext<AutoConnectContextState>({} as AutoConnectContextState);
export function useAutoConnect(): AutoConnectContextState {
return useContext(AutoConnectContext);
}
export const AutoConnectProvider: FC<{ children: ReactNode }> = ({ children }:any) => {
// TODO: fix auto connect to actual reconnect on refresh/other.
// TODO: make switch/slider settings
// const [autoConnect, setAutoConnect] = useLocalStorage('autoConnect', false);
const [autoConnect, setAutoConnect] = useLocalStorage('autoConnect', true);
return (
<AutoConnectContext.Provider value={{ autoConnect, setAutoConnect }}>{children}</AutoConnectContext.Provider>
);
};
then in whichever file you have your WalletContext wrap it with the AutoContextProvider
export const ContextProvider: FC<{ children: ReactNode }> = ({ children }) => {
return (
<AutoConnectProvider>
<WalletContextProvider>{children}</WalletContextProvider>
</AutoConnectProvider>
)
}
Hopw this helps :)
You can also specify the autoconnect attribute on the WalletProvider component to automatically attempt to reconnect a user wallet upon a page refresh.
import { ConnectionProvider, WalletProvider } from '#solana/wallet-adapter-react'
<WalletProvider wallets={wallets} autoconnect>
<WalletModalProvider>
<App />
</WalletModalProvider>
</WalletProvider>
I use react-i18next in my project to provide proper translations, in most components I import
const { t } = useTranslation();
to provide proper content however I wanted to write custom translationWrapper where I would use useTranslation hook and just reuse that component where I need. However it keeps throwing error:
Uncaught TypeError: TranslationWrapper__WEBPACK_IMPORTED_MODULE_16_
is undefined
Why does it happen? Interesting is that if project is running and I add it then it works correctly but when I refresh browser then get above error
My Custom wrapper:
import React, { FC } from 'react';
import { Typography, TypographyProps } from '#mui/material';
import { TFunction } from 'react-i18next';
import { useTranslation } from 'react-i18next';
import { styled } from '#mui/styles';
import { TOptions } from 'i18next';
export type TextContentPath = Parameters<TFunction<'translation'>>[0];
export interface TranslationWrapperProps extends TypographyProps {
content?: TextContentPath;
tParams?: TOptions<{}>;
onClick?: () => void;
}
const TranslationWrapperComponent: FC<TranslationWrapperProps> = ({ content, tParams, onClick, ...materialProps }) => {
const { t } = useTranslation();
return (
<Typography {...materialProps} {...onClick}>
{t(content as TemplateStringsArray, tParams)}
</Typography>
);
};
export const TranslationWrapper = React.memo(TranslationWrapperComponent) as typeof TranslationWrapperComponent;
and try to reuse it here:
export const MyComponent: React.FC = () => {
return (
<StyledSwitchBox>
<StyledTester
variant="p"
sx={{ cursor: 'pointer' }}
onClick={() => console.log('test')}
content={'myComponent.switchContent'}
/>
</StyledSwitchBox>
);
};
const StyledTester = styled(TranslationWrapper)({});
I'm using react-hook-form with typescript and have the code like below. Is there any way to dynamically set type to react-hook-form useForm<DynamicType>() based on the value of categories props or at least not to repeat code like I am doing now?
What I want to achieve:
type DynamicType = Background | Project
if (category === 'background') {
return DynamicType as Background
} return DynamicType as Project
const form = useForm<DynamicType>()
My current code:
import React from 'react';
import { useRouter } from 'next/router';
import { useForm } from 'react-hook-form';
import type { Background } from '../../../../types/Background';
import type { Project } from '../../../../types/Projects';
import {
useBackgroundMutation,
useQueryBackground,
} from '../../../../utils/background';
import {
projectFormDefaultValues,
backgroundFormDefaultValues,
} from '../../../../utils/data';
import { getAsString } from '../../../../utils/helper';
import {
useProjectsMutation,
useQueryProjects,
} from '../../../../utils/projects';
import HookForm from './HookForm';
type Props = {
category: string;
};
const FormTemplate: React.VFC<Props> = (props) => {
const { category } = props;
const router = useRouter();
const id = getAsString(router.query.id!);
const queryBackground = useQueryBackground(id);
const queryProject = useQueryProjects(id);
const backgroundForm = useForm<Background>();
const projectForm = useForm<Project>();
const backgroundFormReset = backgroundForm.reset;
const projectFormReset = projectForm.reset;
const projectsMutation = useProjectsMutation(
projectFormReset,
projectFormDefaultValues
);
const backgroundMutation = useBackgroundMutation(
backgroundFormReset,
backgroundFormDefaultValues
);
return (
<div>
<HookForm
category={category}
categories={}
query={category === 'background' ? queryBackground : queryProject}
form={category === 'background' ? backgroundForm : projectForm}
mutateFunction={
category === 'background' ? backgroundMutation : projectsMutation
}
/>
</div>
);
};
export default FormTemplate;
I have created a separate file for classes prop for e.g. MuiAlert
What is the way to tell makeStyles that you are only allowed to use Alert classes?
The following works but I am sure there must be a better way. So e.g. If I rename root to roott, I will get error that 'roott' does not exist in type 'Partial<Record<AlertClassKey, any>>'
Playground example: https://codesandbox.io/s/typescript-react-material-ui-3t7ln?file=/src/index.ts
import { Theme, makeStyles } from "#material-ui/core";
import { AlertClassKey } from "#material-ui/lab/Alert";
export const useAlertClasses = makeStyles<Theme>(
(): Partial<Record<AlertClassKey, any>> => ({
root: {
borderRadius: 3,
}
}));
my solution:
import { Theme } from "#material-ui/core/styles/createMuiTheme";
import { StyleRules } from "#material-ui/core/styles/withStyles";
import { makeStyles } from "#material-ui/core/styles";
import { createStyles } from "#material-ui/core/styles";
import { AlertClassKey } from "#material-ui/lab/Alert";
export const alertOverrides = (
theme: Theme
): Partial<StyleRules<AlertClassKey>> => {
return {
root: {
backgroundColor: "red !important",
},
};
};
export const useAlertStyles = makeStyles<Theme, {}>(
(theme) => {
return createStyles(alertOverrides(theme) as never);
},
{ name: "MuiAlert" }
);
I am missing something simple but major here. I cannot get the button to just mark a favorite on the list of my stories that I have. can anyone see what I am missing?
import React from 'react'
import { connect } from 'react-redux'
import { Link } from 'react-router-dom'
const MyStories = props => {
const storyBriefs = props.stories.length > 0 ?
addFavorite = () => {
props.stories.map(t => (<p key={t.id}><Link to={`/stories/${t.id}`}>{t.attributes.title}</Link>
<button onClick={this.addFavorite}>Favorite</button>
</p>)):
null
return storyBriefs
}
const mapStateToProps = state => {
return {
stories: state.myStories
}
}
export default connect(mapStateToProps)(MyStories)