Can "font-variation-settings" be used in the styled-components .attrs method? - javascript

I'm trying to pass a variable "width" to a component using styled components. The value of "width" is a function of the mouse position. Passing it directly into the literal string causes styled-components to create a new class for every mouse movement, which throws a warning.
To resolve it, I'm trying to use the .attrs method to pass a variable style object to the component, but I can't work out how to pass this css property to the component.
I tried:
const StyledComponent = styled.div.attrs((props) => (
{
style: {
fontVariationSettings: `wdth: ${props.width})`,
},
})
)``;
But React doesn't recognise this as a valid property to pass into CSS. Any way around it?

Got it. Typical that it's always straight after posting a question after spending hours trying different stuff. Rather than using font-variation-settings, I can use the individual properties. Width becomes font-stretch.
So what I am looking for is
const StyledComponent = styled.div.attrs((props) => (
{
style: {
fontStretch: `wdth: ${props.width})`,
},
})
)``;

Related

Overriding onClick in React

This is somewhat of weird question. I'm working with event types in React, and we want to use onClick in some instances, and onPointerDownCapture in others (for reasons). But to make this more general, it could be any two different click-like events. The issue is that while we can assign whatever function handler on the right side of the expression, the left side has to be static, essentially. So,
<button
onClick={handler} vs onPointerDownCapture={handler} vs onMouseDown={handler}
/>
I think just using onPointerDownCapture will be fine for most usecases, but in a perfect world, I'd be able to flip between these at runtime based on other variables. Is it possible to override the onClick on the button/div/whatever prototype or something to be whatever event type I want it to be?
Much googling. No success.
I didn’t fully understand what you mean by “overriding onClick”, but
The issue is that while we can assign whatever function handler on the right side of the expression, the left side has to be static, essentially.
This is not true, left hand side could be dynamic, here’s how:
<button {...({ [eventName]: handler })} />
I guess this solves your problem.
Ok above syntax is a bit terse and admittedly confusing. It’s the good old JSX spread props syntax, just over an inline object literal.
I’ll give you another equivalent form, hopefully it should be more readable.
const eventName = someCondition ? "onPointerDownCapture" : "onClick"
const props = {
[eventName]: handler
}
<button {...props} />
You have to use those attribute names and you use the same function name for all 3 of them.
What these 3 attributes do is they register the associated event.
Maybe you could use a useEffect and add there conditionally an event listener instead of the proposed React attributes.
I think best is #vera solution in comment. Pass extra prop to component (for example isOnClick), and based on it pass either callback or undefined to event handler prop:
function Component(props: { isOnClick: boolean; callback: () => void }) {
return (
<div
onClick={props.isOnClick ? props.callback : undefined}
onMouseDown={props.isOnClick ? undefined : props.callback}
/>
);
}
Note that passing undefined to prop is same as not setting that prop.
Alternatively conditionaly return component:
function Component(props: { isOnClick: boolean; callback: () => void }) {
if (props.isOnClick) {
return <div onClick={props.callback}/>
} else {
return <div onMouseDown={props.callback}/>
};
}

Replacing document.createElement() with React.createElement()

I have a javascript library which uses document.createElement() which creates an HTMLElement
I want to create a react library with the same functionality.
My idea was to replace the document.createElement() with React.createElement() .
So , the original code which was something like
this.myElement = document.createElement("input");
/* some stuff happens here due only after which the followig code is run */
this.myElement.className = "someClassName";
this.myElement.style.display = "block";
this.myElement.appendChild(someElement);
will become
this.myElement = React.createElement("input");
this.myElement.props.className = "someClassName";
this.myElement.props.style.display = "block"; // Props is read only at this point
this.myElement.appendChild(someReactElement); // This doesn't work either
The problem here is that props is a read only property in react , also appendChild doesn't work that way in. So changing it after React.createElement("input") is not possible. I can create the props object before each createElement call based on the original code but it significantly reduces reusability of the existing code base. Is there a way around that can be used to bypass this issue in react ?
Edit : I know I can pass children and props during the time I call React.createElement however , it reduces my ability to copy paste and reuse the existing code base . The question is specific about changing props and appeding child after the React.createElement call
Create a props object and pass that as the 2nd argument of the createElement function. Follow this-
const props = {
className: 'someClassName',
style: {
display: 'block',
width: '100%'
}
}
React.createElement('input', props);
Read the documentation for React.createElement. You can pass the props (and children) in the function.

Updating Reacts Context values from Class Components

I have a Class Component in a React App. It works. Then I need a global variable and reached to the React's Contexts. I create Context and can consume its value.
But I need to update its value, I read a lot and it seems I have to use React Hooks to update Context value. But my components are Class Components and there I cant use hooks.
My question is, If I want to use Contexts, I cant use Class Components? Right now Im learning React and encountered to Hooks many times. If hooks very important thing, This means we have to use Function Components all the times?
What I have to do? I just need to update my global variable and use its value.
If I want to use Contexts, I cant use Class Components?
No, you can use context either in Class Components.
See Context section in docs, all examples are with classes.
We have to use Function Components all the time?
No, you can use any approach you see fit.
But, there is no actual reason to use Class Components any more (except implementing Error Boundary). React officially recommends using hooks and composition, therefore the preferable approach is Function Components.
What I have to do? I just need to update my global variable and use its value.
A global variable as the name stands, its global to the application's scope (and not bound to component's scope like state). You can update it from everywhere.
const globalObject = { name: `myVar` };
// Can be updated from any scope as you keep the reference.
const FunctionComponent = () => { globalObject.name=`a`; return <></>; }
// Outer scope
globalObject.name=`b`;
Please visit this link, https://www.taniarascia.com/using-context-api-in-react/ and How to update React Context from inside a child component?.
it is explained in this link, you can do this way :
class LanguageSwitcher extends Component {
render() {
return (
<LanguageContext.Consumer>
{({ language, setLanguage }) => (
<button onClick={() => setLanguage("jp")}>
Switch Language (Current: {language})
</button>
)}
</LanguageContext.Consumer>
);
}
}

Highlighting value change ReactJS

I am using ReactJS, and I was wondering whether it is possible to highlight an element in the DOM when its value has been changed.
I have a list of elements whose values update periodically. While I have no problem animating in the DOM new items coming in to the list or items leaving the list using React's animation library interface, I am struggling to figure out how to detect the actual value change of the existing elements in the list.
Any ideas on how to do so? Thank you!
I had the same problem, then I decided to create a generic small module to handle it everywhere, that you can install from here
https://www.npmjs.com/package/react-change-highlight
using
yarn add react-change-highlight
what you can do to use it is to wrap you part that you want to highlight inside the component itself as follow
import ChangeHighlight from 'react-change-highlight';
export default () => {
const [count, setCount] = useState(0);
return (
<ChangeHighlight>
<div ref={React.createRef()}>{count}</div>
</ChangeHighlight>
);
}
and you will find the highlight on change as in the example below
I hope you find this useful
If your new values are coming down as new props, then you can use the componentWillReceiveProps lifecycle method on the component. It is called just before the component is updated.
Within that method, you can compare the new values (passed as the argument to the method) and the old values (available as this.props).
For instance:
componentWillReceiveProps: function(newProps) {
if(this.props.query != newProps.query) {
//handle change of query prop
//may include calls to this.setState()
}
}
Assuming that your elements are input elements, you need to use the onChange event listener. If you want to highlight that element, I would suggest having a CSS class that highlights the element and then conditionally applying it in render() based on state (or props if a child).
So for instance, you can have one component, add a handler function and the appropriate listener in the render():
handleChange: function(evt) {
//input was changed, update component state (or call parent method if child)
this.setState({changed: true});
},
render: function() {
return (<div>
<input type="text"
className={this.state.changed ? 'highlight' : ''}
onChange={this.handleChange}
/>
</div>);
}
That should set you in the right direction.

Setting a field directly on the class definition in ReactJS

Is it a good practice to do this in ReactJS?
var Component = React.createClass({
render: function () {
return (<div></div>);
},
field: 'value', // is this safe?
method: function () {
// do something with field
}
})
Before starting to suggest that I should use this.props or this.state, for me it's not the case, because those are fields that do not affect rendering in any way directly, they just work together to control the rendering.
I would like to use the React class as I do with regular javascript 'classes'.
My main concern here is how those fields and methods are handled inside React, and if the fields are set on the instance itself or directly on the prototype, which would not be suitable at all for what I need.
I ran a quick test and it seems that the fields are set on the instance, and the methods on the prototype, which is ideal. But is this the expected and documented behavior? And is this safe for future versions?
I think it can work the way you are doing and that it's safe. However if I understand well you are proceeding data calculation/transformation directly in the view.
So I would advise that you remove this logic from the view and treat it in the model part of a mvc or mv*, in your backbone models, or in your flux store for example.
This way you won't be mixing data transformation logic and pure rendering.
I would say so, I have been using things like this for a while and have not seen any issues. For example, let's say you want a handler of some sort that you want to pass to nested components, you would create the function in this component and pass it as a prop to a child. I believe they have examples that use similar concept in the ReactJS Facebook site.
Under the hood React is just looping through the properties of the object you pass to createClass and copying them to the prototype of the Component. Primitive values like strings or numbers obviously cannot be copied by reference, so don't get shared across all instances, whereas objects, functions, arrays and so on will.
If you want to work with values that are just local to the component instance you need to use the state API. I'm not sure what you mean by "[state and props] do not affect rendering in any way directly, they just work together to control the rendering". The whole point of props and state is that they work together to generate values to be used when (re)rendering.
https://facebook.github.io/react/docs/component-api.html
A React component should only render in response to either changing props or changing state. You cannot/shouldn't trigger a re-render by mutating other fields directly.
You need to think of your component as something closer to a pure function. State and props go in at the top, and static VDOM/HTML comes out.
I would re-write your example as,
var Component = React.createClass({
getInitialState: function () {
return {field: 'value'};
},
render: function () {
var field = this.state.field;
return (<div>{field}</div>);
},
method: function () {
var field = this.state.field;
// do something with field
this.setState({field: 'anotherValue'});
}
})

Categories