store a javascript value to less variables + reactjs - reactjs

I am trying to fill less variable value with a js variable from an html page in reactjs based app.
index.html
<script>window.baseColor = '#000000'//Color value will be dynamic</script>
style.less
#baseColor: window.baseColor

I don't think this is possible but you can do it using inline style and if you are going to use it in multiple components you can use the new context API
const BaseColorContext = React.createContext('#000000')
class ColorProvider extends React.Component {
state = {baseColor: '#fff'}
render() {
return (
<BaseColorContext.Provider value={this.state.baseColor}>
{this.props.children}
</BaseColorContext.Provider>
)
}
}
class App extends React.Component {
render() {
return (
<ColorProvider>
<BaseColorContext.Consumer>
{val => <div style={{backgroundColor:val}}>content here</div>}
</BaseColorContext.Consumer>
</ColorProvider>
)
}
}

Related

How can I pass state to grandparent so that uncle/aunt can use it?

I've been struggling for hours trying to get some code to work. I'm new with React, but I have spent a lot time looking for a solution to this as well, and updating this code as I understood with no success.
Basically my app is a component that splits into two components, with one of those splitting into 9 buttons. When I click one of those buttons, I want its uncle/aunt to recognize that, and use the id of the button that was pushed to create a message.
I figured I should be passing the button id up to the grandparent so that it can pass the id down to the uncle/aunt. But its the passing the id to the grandparent I'm struggling with.
This is the general set up below:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
"x" : " "
};
getX(x){
this.setState({"x": x})
}
render() {
return (
<div>
<A getX={this.getX}/>
<B x={this.state.x} />
</div>
)
}
}
const A = (props) => {
const getX = (x) => props.getX(x);
a = [];
for (let i=0; i<9; i++) {
a.push(<C id={i} getX={getX}/>);
return <div>{a}</div>
}
class C extends React.Component {
constructor(props) {
super(props);
this.state = {
"id" : props.id,
"getX" : (x) => props.getX(x)
}
this.handleMouseDown = this.handleMouseDown.bind(this);
}
handleMouseDown(e) {
this.state.getX(e.target.id);
}
render() {
<div />
}
}
class B extends React.Component {
constructor(props){
super(props);
this.state = {
"x" : props.x
}
}
render() {
return <div>{this.state.x}</div>
}
}
Firstly, the getX() method of the App component doesn't seem to be working how I expected it to. By that I mean, when I add getX("7"); to the render method of the App component, just before the return statement, the whole thing crashes. But if I replace this.setState({"x": x}) with this.state.x = x in the getX() method, then the state sucessfully passes down to the component B, which is something at least. But, I don't understand why.
Secondly, I can't work out how to modify the App component's state from within component A. The getX() method of the App component doesn't seem to be passed into component A as I expected. Again, if I insert getX("7"); before the return statement of component A, the whole thing crashes again. I expected the getX function of component A to be the same function as the getX method of the App component, and therefore update the state of the App component. But I've had no success with that at all. I've even tried inserting this.getX = this.getX.bind(this) into the constructor of the App component, but that didn't solve everything for me.
Lastly, as you can probably guess, I cant modify the App component's state from any of the C components.
Any ideas? I'm stumped.
I have modified your example so that it works. A few things:
Dont copy props to state, that is an antipattern and creates bugs (as you have seen). Dont copy the id or the function passed from component A to component C, or in component B. Just use the props values.
You had some syntax errors that I fixed.
You didnt return the array created in component A.
(This is my preference, but I will argue that you are setting a value, not getting, so i renamed getX to setX.)
There was nothing returned from component C. I was not sure what you was suppoosed to be returning from that component, so I just created a button with a click-handler.
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
x: '',
};
this.setX = this.setX.bind(this);
}
setX(x) {
this.setState({ x: x });
}
render() {
return (
<div>
<A setX={this.setX} />
<B x={this.state.x} />
</div>
);
}
}
const A = (props) => {
let a = [];
for (let i = 0; i < 9; i++) {
a.push(<C id={i} setX={props.setX} />);
}
return <div>{a}</div>;
};
class B extends React.Component {
render() {
return <div>{this.props.x}</div>;
}
}
class C extends React.Component {
constructor() {
super();
this.handleMouseDown = this.handleMouseDown.bind(this);
}
handleMouseDown() {
this.props.setX(this.props.id);
}
render() {
return <button onClick={this.handleMouseDown}>Click me</button>;
}
}

Rendering a Constant Inside of a React Class Component

I have a quick question regarding the way to render content using constants in a React class component. So the following code works fine (rendering a constant using the map function):
class App extends React.Component {
array = [
{
name: "Sarah",
age: 27
},
{
name: "Sam",
age: 35
}
]
render() {
const output = this.array.map(elem => (
<div>
<p>{elem.name}</p>
<p>{elem.age}</p>
</div>
));
return (
<div>{output}</div>
);
}
}
However, the following produces a blank page (I am simply defining a constant that returns a div and trying to render it):
class App extends React.Component {
render() {
const Output = () => (
<div>Hello</div>
);
return (
<div>{Output}</div>
);
}
}
But virtually identical code works if instead of the curly braces I use the angular ones:
class App extends React.Component {
render() {
const Output = () => (
<div>Hello</div>
)
return (
<div>
<Output />
</div>
)
}
}
So it seems like this has something to do this curly and angular brackets. Curly braces work when I use a map function but do not when I define a constant that returns a div inside a render method and try to render it directly. Then it works again when I use angular brackets... This is kind of strange. I understand that this is far from the most important thing, I'm just trying to get to the bottom of this. Thank you in advance!
Angular brackets are used to render components. Since you've defined Output as a function which returns some JSX, this makes it a function component as far as React is concerned (or rather Babel, which handles the transpilation of your JSX).
You can use curly brackets but then you should change Output to a React node. Here's how you'd do that:
class App extends React.Component {
render() {
const Output = <div>Hello</div>
return (
<div>{Output}</div>
);
}
}
Check THIS answer for some clarification regarding the difference between React nodes, elements etc.
class App extends React.Component {
render() {
const Output = () => (
<div>Hello</div>
);
return (
<div>{Output()}</div>
);
}
}
if you try to call a function Output() it will return the JSX but follow this article they dont recommend that

React map redux state to create multiple components within a component

I am using the react-redux-mapbox-gl library. I have an array of spots that I want to map in order to create multiple overlay components within the Mapbox Component. However on trying to map the array I always get an undefined error. I am new to React/Redux so am not sure what the issue is.
My Component Below:
import React from 'react';
import Mapbox from 'react-redux-mapbox-gl';
import SpotsOverlay from './SpotsOverlay'
const mapStateToProps = state => ({
spots: state.homemap.spots
})
class HomeMap extends React.Component {
render(){
return (
<Mapbox
mapboxgl={mapboxgl}
accessToken={mapAccessToken}
getMap={this.getMap}
style={this.mapStyle}
options={this.mapOptions}
>
{
this.props.spots.map(spot =>{
return (
<SpotsOverlay
overlay={this.overlay}
key={spot.id}/>
);
})
}
</Mapbox>
);
}
}
Do the mapping outside of the return method might help.
class HomeMap extends React.Component {
render(){
let spots = [];
if(this.props.spots) {
spots = this.props.spots.map(spot =>{
return (
<SpotsOverlay
overlay={this.overlay}
key={spot.id}/>
);
});
}
return (
<Mapbox
mapboxgl={mapboxgl}
accessToken={mapAccessToken}
getMap={this.getMap}
style={this.mapStyle}
options={this.mapOptions}
>
{spots}
</Mapbox>
);
}
}
As #MayankShukla said in his comment, the reason why this works better is that
initially reducer state is {}, so state.homemap.spots will be undefined and when you were using map of undefined

React.js - setState after calculation based on props

I have a component that receives images as props, performs some calculation on them, and as a result I need to update its class. But if I use setState after the calculation, I get the warning that I shouldn't update state yet... How should I restructure this?
class MyImageGallery extends React.Component {
//[Other React Code]
getImages() {
//Some calculation based on this.props.images, which is coming from the parent component
//NEED TO UPDATE STATE HERE?
}
//componentWillUpdate()? componentDidUpdate()? componentWillMount()? componentDidMount()? {
//I CAN ADD CLASS HERE USING REF, BUT THEN THE COMPONENT'S
// FIRST RENDERED WITHOUT THE CLASS AND IT'S ONLY ADDED LATER
}
render() {
return (
<div ref="galleryWrapper" className={GET FROM STATE????}
<ImageGallery
items={this.getImages()}
/>
</div>
);
} }
You should put your logic into componentWillReceiveProps (https://facebook.github.io/react/docs/component-specs.html#updating-componentwillreceiveprops) so as to do a prop transition before render occurs.
In the end what we did was run the logic in the constructor and then put the class into the initial state:
class MyImageGallery extends React.Component {
constructor(props) {
super(props);
this.getImages = this.getImages.bind(this);
this.images = this.getImages();
this.state = {smallImgsWidthClass: this.smallImgsWidthClass};
}
getImages() {
//Some calculation based on this.props.images, which is coming from the parent component
this.smallImgsWidthClass = '[calculation result]';
return this.props.images;
}
render() {
return (
<div className={this.state.smallImgsWidthClass }
<ImageGallery
items={this.images}
/>
</div>
);
}
}

Passing another component to a React Component

React newbie here.
I am trying to create a simple category tree which allows you to render a JSON structure as a tree. The role of this JSONView is to be aware of the JSON structure and split it down into hierarchical tree. And the nodes of the tree will be parsed according to a custom rendering logic, which can be injected into this panel.
This complies with Single Responsibility Principle in the sense that JSONView is responsible for parsing the data and render the view component at leaves. The view component takes care of the rendering logic. I was able to achieve this by making the view component as a child component of the JSONViewPanel here :
http://jsbin.com/tiwijilide/1/edit?js,output
But I would really like to achieve something like this :
let x = {
"category":["first","second","third","fourth"]
};
class JSONPanel extends React.Component{
constructor(props){
super(props);
}
render(){
let {data, ...x} = this.props;
let dataNodes = data.category.map((category) => {
x = Object.assign(x, {text:category});
return (
<li><Component {...x}/></li> //Component passed as props
)
});
return (
<ul>{dataNodes}</ul>
);
}
};
The intention is to pass in any subtype of React component to this JSONView.
Is it possible without making Node component children of sub component as its done in the JSBin link?
Yes it is possible: try it!
let x = {
"category":["first","second","third","fourth"]
};
class JSONPanel extends React.Component{
constructor(props){
super(props);
}
render(){
let {data, ...x} = this.props;
let Renderer = this.props.renderer.component;
let dataNodes = data.category.map((category,rank) => {
x = Object.assign(x, {text:category})
return (
<li key={rank}><Renderer {...this.props.renderer.props} {...x}/></li>
)
});
return (
<ul>{dataNodes}</ul>
);
}
};
class RenderNode extends React.Component{
render(){
return(
<span className={this.props.will}>{this.props.text}</span>
)
}
}
var renderer={
component:RenderNode,
props:{will:"color-text-green"}
}
React.render(<JSONPanel data={x} renderer={renderer}/>, document.getElementById("react-example"));
The component can be given as props and must be call through a string with a capital first letter.

Resources