Update className using react hook - javascript

I have a span which has a className . The span has two state, one is like
<span key={uuid()} ref = {colorRef} className = 'singleWord'>{word}</span>
and the other is like
<span key={uuid()} ref = {colorRef} className = 'singleWord redword'>{word}</span>
Now what I want is to check the className value like className.classList.contain("oneClass') which we do in vanilla js but I need in react hook(may be with ref hook) and also add className and remove className . also is it possible to check the length of className .for example 'singleword redword' should give length 2.
So overall I need -
add or remove classes
check length
check if class contains or not
I need to check them in react hook
could anybody suggest how to do ??
Thanks in advance

You can store in state an array of classes and use that to get all the information you need plus it gives an easy way to toggle any class in a set of classes.
basically this handleClasses function takes a class argument and then checks whether that class is already in your state. If it is, it removes it, if it's not, it add it to the state. Then in your span you join all the classes in the array in state to make a single string of classes.
Also you get the number of classes applied to your element very easily by doing classes.length
import React, { useState } from 'react';
const Component = () => {
const [classes, setClasses] = useState(['singleWord']);
const numberOfClasses = classes.length;
const handleClasses = (c) => {
setClasses(classes.includes(c)
? classes.filter((cls) => cls !== c)
: [...classes, c]
)
}
return (
<span
onClick={() => handleClasses(passClassToToggleHere)}
className={classes.join(' ')}
>
text
</span>
)
};

If you are using colorRef = useRef() hook, then you can obtain the target node by calling colorRef.current and proceed with vanilla js methods like
colorRef.current.classList.contain("oneClass') and so on.

Related

How to toggle two different buttons (function/text) based on external condition (e.g. num of items purchase)

I am revisiting an earlier idea to toggle between two buttons conditionally in a CRA.
import ...
const ...
export const Index = () => {
// Boolean to toggle buttons conditionally
const [reachMax] = React.useState( id <= 8 );
return (
<div>{(reachMax &&
<div{(reachMax &&
<button
id="btn1"
type="button"
className="..."
onClick={event}
>
Event A: "Sales!"
</button>
</div>)
||
<div>
<button
id="btn2"
type="button"
className=" "
disabled='true'
>
Event B: "Out of Stock"
</button>
</div>)
}
)
}
Using a state hook. The condition for the Boolean ( contract.tokenUri.id <= 8 ) is taken from an external smart contract dynamically. How can the condition be set so that it would not return an undefined error?
You're trying to access this in an arrow function. Besides not knowing what this will point to, in React that's not how you access props in functional components.
I assume you use Index like this in your Toggle component:
<Index data={...} />
Then you access it like:
export const Index = (props) => {
const data = props.data;
// ....
};
Managed to resolve by setting this condition in order to read the ID off the smart contract:
const reachMax = mintedState.state === "SUCCESS" && mintedState.data.length <= 8;
There's no need for the constructor as the state is directly passed into the app from the external contract. Once the nmintedState.state condition is satisfied (success), the data.length (a proxy for the ID) can be used as the final condition for setting the right button.
This problem is specific to the combination of Solidity contract and ReactJS used.

Problems generating random classNames for HTML tags in React

Hello everyone!
This might be a silly question but I can't figure out why the className variable in the console.log has a different value from the one used in the className attribute of the <p>.
I'm trying to generate random class names for HTML tags so then I can create CSSStyleSheets with rules to these HTML tags. Since, in this example, the css prop is the same the styling is working but the className variables in the tag and in console.log are different and that's what I can't understand why.
Am I missing something obvious or is this somehow the intended behaviour?
The code is this:
import React from 'react'
const constructCss = (css) => {
const style = document.createElement('style')
document.head.appendChild(style)
style.appendChild(document.createTextNode(css))
}
const constructCssStyleAndReturnClassName = (css) => {
const generateRandomString = (length=6) => Math.random().toString(20).substr(2, length)
const className = `styled-${generateRandomString(8)}`
constructCss(`.${className} ${css}`)
return className
}
const Pa = ({css, children}) => {
const className = constructCssStyleAndReturnClassName(css)
console.log('Rendering with className: ', className)
return <p className={className}>{children}</p>
}
export default function App() {
return (
<div className="App">
<Pa css={`{ background-color: blue; color: white }`}>Helloooooo</Pa>
</div>
);
}
It's also here in codesandbox
Thanks in advance :)
The Code Sandbox seems too slow to catch it with console.log, but if you set a debugger (or console.count) in your Pa component you will see that you get 2 renders, which means you get two different random class names. I would guess that it logs the first, but then uses the second.

how to stop rerendering in react on checkbox check?

I have simple list which is dynamically added on add button click. in my list there is a checkbox is also present .so I have an issue when I toggle the checkbox my whole list is re render why ?
let take example I added A,B,C,D in my list when I toggle D checkbox it should only render D item currently it render whole list why ?
here is my code
https://codesandbox.io/s/stupefied-wildflower-gv9be
const Item = ({ text, checked, onCheckedHandler }) => {
console.log(checked, "ssss");
return (
<div className={checked ? "bg" : ""}>
<span>{text}</span>
<input type="checkbox" onChange={e => onCheckedHandler(e, text)} />
</div>
);
};
Every time items changes (whether by adding a new item or checking a value), you are creating a new onCheckedHandler in your App. This propagates down to your Item component. Since the previous onCheckedHandler property is not referentially equivalent to the previous one, it renders (and you see that console log for each item). Memoizing the component alone won't help because a property being passed to it is changing every time.
To get around that, you need to memoize the onCheckedHandler, try this:
const onCheckedHandler = useCallback((e, selectedText) => {
const target = e.target
setItems(items => {
const i = items.findIndex(i => i.text === selectedText);
let obj = items[i];
obj.checked = target.checked;
return [...items.slice(0, i), obj, ...items.slice(i + 1)];
})
}, [setItems])
The you can wrap your Item compoennt with React.memo, and it should work as expected. You'll also need to import the useCallback the same way you import useState

ReactIntl.FormattedPlural Component to String

I am new to React.
I used ReactIntl.FormattedPlural to format the plural.
<FormattedPlural
value={10}
one='message'
other='messages'
/>
It works when I place this component in the render() function. However, I have a scenario that I want to get the String and passed into a function.
Instead of Using {value ==1 ? 'message' : 'messages'}, can I use ReactIntl.FormattedPlural to achieve this?
In any case, in the end you need to put it into the render.
Because the FormattedPlural is a component. To display it, you need to render it. It's how React works.
You can save it as variable:
const text = (<FormattedPlural value={10} one='message' other='messages' />)
For example if you have a condition and need to decide which string to render.
But in the end, the text should passed to the render to be displayed for user.
Derived from FormattedPlural implementation:
const { formatPlural } = useIntl()
// get the plural category ("one" or "other")
const pluralCategory = formatPlural(count);
const options = {
one: "message",
other: "messages",
}
const plural = options[pluralCategory as 'one'] || options.other;
See also: https://formatjs.io/docs/react-intl/api/#formatplural

Change style dynamically, without resetting when re-rendered in React

I have a page of just a list of divs calling an onClick function. Pretty much this...
<div
className="square card-container bg-primary"
points="200"
id="2"
onClick={e => select(200, "cat1", e.target.id)}
>
<h3 className="text-light">200</h3>
</div>
Just 30 of them. With sequential ID's. It's easy enough to push the ID's to a new array when clicked, or to add className once they're clicked, and when I step through the code in Debugger I can see that the class is Added and the styles change, but it is immediately set back to the previous "Un-clicked" className. I was thinking that it might work to make each of these div it's own component and than use useState, but since they're all mostly identical I would still need a key or id, so I'm not sure how I would pass that in to a state and use that conditionally? I'm sorry if this doesn't make sense. Basically I just want to change styles slightly once an item has been selected, without going back to the initial className when it is re-rendered.
This is the script that gets called onClick.
const selected = []
const change = id => {
selected.push(id);
console.log(selected);
};
const select = (points, cat, id) => {
let newArr = questions.filter(
q => q.category === "Sample 1" && q.points === points
);
change(id);
if (newArr.length > 1) {
let randomOutput = Math.floor(Math.random() * newArr.length);
console.log(newArr[randomOutput]);
let out = newArr[randomOutput];
props.setQuestion({ out });
props.detail();
return out;
} else {
let out = newArr;
props.setQuestion({ out });
props.detail();
console.log(points, cat);
}
}
You need to store a list of selected items using state and make className dynamic
Example: https://jsfiddle.net/78bsnhgw/

Categories

Resources