Identify current theme of MS Teams in react bases component - reactjs

I am working on the MS Teams app where I have a page in which I want to identify current MS Teams theme (default, dark or high contrast).
I have added this https://www.npmjs.com/package/msteams-react-base-component dependency where it explaining how we can extract teams theme. Below is my code snippet which always giving me themeString as default.
export default function FioriTab(): ReactElement {
const [{ themeString }] = useTeams({});
useEffect(() => {
console.log(themeString)
}, [themeString]);
}
Any idea what I am doing wrong here.
I tried adding setThemeHandler which also returning theme as undefined.

With respect to Wictor, I don't know much about that library you're referencing, but according to the docs on this one (https://github.com/OfficeDev/TeamsFx), it's based on his anyway and probably better maintained, considering. It also has a useTeams hook that aims to do the same thing.
If you have a totally new solution anyway, perhaps best is to start with the Teams Toolkit in any case, as it will scaffold this for you.
On a separate but related note, see that useTeams also allows you to send a theme handler - this is important to handle theme changes while a user is using your apps - Teams will let you know the theme has changed so you can respond accordingly.
With regards your main question, the reason you're always seeing the "default" theme, from what I can see in the code for this framework, is because of the asynchronous setting of the theme state over here. It can be easily solved, per my suggestion above, of implementing the theme change event handler that you need to implement anyway. Basically, you should have something like this:
export default function FioriTab(): ReactElement {
const [themeString, setThemeString] = useState<string>("default");
const [{ inTeams }] = useTeams({}, (theme: string | undefined) => {
setThemeString(theme || "default");
});
...

Related

Avoid magic strings when working with Chakra Ui

A problem, I keep running into with Chakra Ui are "magic strings". Let's look at an example of muted text:
function Example() {
const color = useColorModeValue("gray.400", "gray.200");
return (
<Text color={color} />
)
}
What's the problem with this code: In my app, I want to share the muted color between many components. However, defining it explicitly as a string means that I have to remember that muted text has a value of "gray.400". If I have another component that wants to use muted text, I have to copy the string "gray.400" to all other components. I will end up with lots of strings that make it really hard to change things across the entire app. I explored two solutions so far:
Solution 1 - TextStyles API: Chakra comes with a textStyles API out of the box but this doesn't work well for more complicated situations (what if I want to have a hover and active state with different colors?).
Solution 2 - Create a global object: I've created a hookuseConsistantStyles() that returns a theme-like object with values, e. g.: {"borderLight": "gray.200"}. However, this feels like I'm fighting the library.
I'd really love to have a better solution since I keep running into this.
This is probably late but for any new onlookers, since Styled System v1.17.0, chakra ui has semantic tokens. The changelog and docs have some details but the important bit is:
Semantic tokens provide the ability to create css variables which can change with a CSS condition.
CSS conditions would be states like dark mode or hover etc.
In this case, you would define a semantic token like so (with a better token name):
const customTheme = extendTheme({
semanticTokens: {
colors: {
nicelyNamedToken: {
default: 'gray.400',
_dark: 'gray.200',
},
},
},
})
import the theme however you currently do, and then anywhere the theme is present, you should be able to just use the token
function Example() {
return (
<Text color='nicelyNamedToken' />
)
}
I don't think Solution 2 is actually that bad -- but I agree that it feels like everything should be accessible since it already exists.
If you're using a chakra theme, you can actually import the theme (i.e: import { theme } from "#chakra-ui/react"
And then you can start accessing things off of that object, like colors (t is the theme import)
Note: you still have to 'know' the keys on the object, but this is at least an existing, consistent dictionary that you can reference.
I have not tested this with different color themes, etc.

Is this a dumb idea for how to simplify redux + react?

I'm trying to refactor an app to use redux toolkit but I'm running into an infinite loop when dispatching an action to set state and I suspect its because I'm not following the conventions.
What I'm attempting to do at a high level is have a useAppHandlers hook that returns all the handlers for the entire app. Similarly, I have a useAppState hook that returns a global object with all my state. Snippet from my config file:
export const useAppState = () => {
const coingeckoApiState: AppState[typeof coingeckoApi.reducerPath] = useSelector(state => state.coingeckoApi);
const connectionState: AppState['connection'] = useSelector(state => state.connection);
const currencyState: AppState['currency'] = useSelector(state => state.currency);
return { ...coingeckoApiState, ...connectionState, ...currencyState };
};
export const useAppHandlers = () => {
const connectionHandlers = useConnectionHandlers();
const currencyHandlers = useCurrencyHandlers();
return { ...connectionHandlers, ...currencyHandlers };
};
^^Does that look problematic? I unfortunately can't share the full repo because it's private.
In all the redux examples I've come across, people import useDispatch in addition to the actions they are dispatching within each component. I really don't like how it results in so many lines of code just for imports and set up ex:
const dispatch = useDispatch() repeated ad nauseam across the repo).
This repo is a real-world example of what I'm trying to avoid:
https://github.com/Uniswap/uniswap-interface/blob/4078390a4890445d1ff0ed5196fd4cb56a44de87/src/components/NavigationTabs/index.tsx#L116
Before I give up and just follow conventions, I'd like to pinpoint if the above way I'm configuring redux is the source of the infinite loops, or if its a random bug I introduced deeper in the code.
Honestly, just don't. You will never be able to bundle-split in the future if the need for that arises when creating such a god-object. Also, adding something now means you have to touch at least one more file that is not using that something - same goes for deleting.
In addition to that, writing so "wide" selectors that select a full slice, even if your components only ever consume a part of that slice is a horrible thing for your performance - those components will always rerender if anything in that slice changes, no matter if it is important for your component.
Lastly: Just ignore your imports and let your IDE take care of it for you, probably out of the box. Your IDE can auto-import them for you. You can configure your IDE (with eslint autofix or other plugins) to automatically sort your imports alphabetically and also remove unused imports on save. I'm sure there is even a plugin that will just collapse your imports for you if you don't want to see them.
PS: as for why in react-redux you usually import useDispatch everywhere, you can read a bit on the history of that decision here: https://react-redux.js.org/api/hooks#recipe-useactions

Devtools for React Easy State?

i just switcher from redux, is there any tooling available, to inspect or even manipulate the react Easy State stores for dev purpose or do you have any good practice Tipps to do so?
Is ist maybe possible to console.log the current State on every change?
We don't have a devtool yet but it is an often requested feature. It's on our agenda and we are already collecting data about what people expect from a devtool. Sooo... what are the must-have features in a React state devtool to you?
About the timeline: we will release better docs, a linter, and probably strict-mode before a devtool. We already have a very basic devtool primitive (which just logs a lot of data) that could be used in the meantime. It would never be an official API though and we would just remove it in a later release. Are you interested? Should we release it as a temporary solution?
Is ist maybe possible to console.log the current State on every change?
Sure:
import { store, autoEffect } from '#risingstack/react-easy-state'
const myStore = store({
name: 'Bob'
})
autoEffect(() => console.log(JSON.stringify(myStore, null, 2)))
// logs `{ name: 'Ann' }`
myStore.name = 'Ann'
(I am an author of React Easy State)
If you're using global stores, e.g.:
const myStore = store({
a: 1
});
You can assign them to the window object so in your chrome/firefox devtools you could do something like:
window.__EASY_STORES__ = {
MY_STORE: myStore
}
You can then mutate that object in the console and it should be reflected in the rendering if your components are wrapped in view.
Other than that there's currently discussion around building a whole suite of devtools in the community, but at the moment we don't provide any out of the box inspector or dev tooling around the library.
It is indeed possible to log state changes using middleware. A simple logging middleware can look like this (it's typed in Flow):
export default (store: Store<ReduxState>) => (
next: (action: Action) => ReduxState
) => (action: Action) => {
console.log(`dispatching: ${action.type}`)
const result = next(action)
console.log(`next state: ${JSON.stringify(store.getState())}`)
return result
}
Manipulating is another thing. You could eather create a "cli" - I've recently done this in a project. It's basically just a JS function exposed to the browsers console.
Or, what I would suggest is using a browser plugin. The most commonly known is probably "Redux DevTools" which is available at least for Firefox and Chrome. It gives you CRUD-control (create, read, update, delete) over redux-state.
Edit: Since I fataly misread your question, this comment on GitHub might interest you. Seems not to have very active maintainers^^ But sorry, I don't know anything about easy-state.

Binding properties of an array in an array

This is not to start a discussion about Anugular vs REACT. I know at some point I will learn to love REACT. That is why I have started doing new apps in REACT. I just need some kind of confirmation whether I understand REACT correctly according to bindings.
I am making a function REACT component (arrow function) as I can read this is the new recommended practice. I have some data with an array of data with arrays of data. I am using all of this data to show and change content. In this specific sample I use it to toggle some menu's.
In Angular in the toggle you would have something like:
toggle(row){
row.toggle=!row.toggle;
}
As I understand it in REACT, if you want to change content, or have some states about toggle you need hooks (correct me if I am wrong). So in REACT you would apply all of your data to a setData(someData). Something like below:
const toggleMenu = (section, row) => {
console.log(section);
setDataList(
dataList.map(s => {
return s.id === section.id
? {
...s,
table: s.table.map(t => {
return t.id === row.id
? { ...t, toggleDropdown: !row.toggleDropdown }
: t;
})
}
: s;
})
);
};
So I have to find my specific objects in my data, update it, and pass it all back to the hook setter. I have two concerns here. Sometimes I meet customer requirements where they want tons of data on a home page (even when it is not best practices). That will still perform with Angular. Anyone has some experience whether REACT will perform in such scenarios with this approach (so much looping)?
Last have I misunderstood something, or is this normal practice when working with REACT - or have I over complicated the task? I have made a small sample here to show a sample case:
https://codesandbox.io/s/dropdown-for-multiple-maps-gmqpp?fontsize=14&hidenavigation=1&theme=dark
The answer I am looking for is Yes this is the way to go, or no you have totally misunderstand the concept because .. And a plus if somebody have experince with the performance for pages with a lot of content.

Office UI Fabric - How to apply css styles to existing components

I'm using the provided components and every time I need to change a component style I wonder what's the proper way to do it.
Lets say I need to change the IconButton background color when it's disabled.
https://codepen.io/elsl/pen/KrQQdV
If I provide a theme, how am I supposed to know which palette/semanticColor is used by that component?
const iconsTheme = Fabric.createTheme({
semanticColors: {
disabledBackground: "#ff9933"
}
});
<Fabric.IconButton
iconProps={{iconName:'ChevronRight'}}
disabled
theme={iconsTheme}
/>
If I provide an IButtonStyles, how am I supposed to know that the property name is "rootDisabled.backgroundColor"?
const iconButtonStyles: IButtonStyles = {
rootDisabled: {
backgroundColor: "#ff0000",
}
};
<Fabric.IconButton
iconProps={{iconName:'CalculatorEqualTo'}}
disabled
styles={iconButtonStyles}
/>
For both these options, I had to dig into the component's source code on github to find out.
Is this the expected/correct way?
If so, between creating a Theme or an IStyle which would be the ideal/best practice?
Theme vs IStyles
I would say, use a Theme if you want all Fabric components to have the same customization.
Use the styles property if you just want to customize that specific component (or that one specific instance of the component).
How to discover the styling hooks if using IStyles
There are four ways that comes to mind.
Look at the documentation (e.g. https://developer.microsoft.com/en-us/fabric#/components/dropdown, look at the IDropdownStyles interface)
(screenshot)
Utilize IntelliSense if you're using an editor like Visual Studio Code, which automatically enumerates the IComponentStyles and provides documentation if any.
Inspecting the DOM often provides hints (the hook areas usually look like {area}-{number} so root-33 for instance where the "area" name is root.
Read the source code.
Unfortunately for option 1 and option 2, Fabric React isn't super consistent with the IComponentStyles documentation so not all components have equally descriptive comments and in those cases, you may need to fallback to option 3 and option 4.

Resources