react how to pass props to inline css style in components - javascript

I need to draw some colored squares and use props to control the color of these squares.
The current code is not working
import React from "react";
class SketchExample extends React.Component {
constructor(props) {
super(props);
}
render() {
const { color } = this.props;
return <div style={{ color: this.props.color, width: "36px", height: "36px" }} />; } }
export default SketchExample;
And the app.js file
import React from "react";
import ReactDOM from "react-dom";
import SketchExample from "./SketchExample";
function App() {
return (
<div className="App">
<SketchExample color={{ r: "201", g: "112", b: "19", a: "1" }} />
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Which part went wrong? Thanks.

Passing color will make the text inside the div of that color.
What you need it backgroundColor to make "colored squares".
Also, you can't pass an object to a styles, it need to be a string.
return (
<div
style={{ backgroundColor: `rgba(${Object.values(this.props.color).join(", ")})`, width: "36px", height: "36px" }}
/>
);

From a quick glance of your code I can see you pass a color prop to SketchExample which is an object with props such as r and g and etc. Yet inside SketchExample the divs style.color is the object, not the actual color. Try something like this:
render() {
const { color } = this.props;
return <div style={{
color: `rgba(${color.r},${color.g},${color.b},${color.a})`,
width: "36px",
height: "36px"
}} />
}

Related

How to update a component based on changes in another component in React

There are two components which don't have parent-child or sibling relationship between them.
One of them build the Toolbar and another one contains a color picker. The idea is to change the color of the Toolbar based on the value set in the color picker.
Here is my code so far:
import React from 'react';
import { Button, Icon } from 'semantic-ui-react';
import { ChromePicker } from 'react-color';
export default class Banner extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
displayColorPicker: false,
background: '#fff',
};
}
handleClick = () => {
this.setState({ displayColorPicker: true });
};
handleClose = () => {
this.setState({ displayColorPicker: false });
};
handleChange = color => {
this.setState({ background: color.hex });
};
handleChangeComplete = color => {
this.setState({ background: color.hex });
};
render() {
const popover = {
position: 'absolute',
zIndex: '2',
};
const cover = {
position: 'fixed',
top: '0px',
right: '0px',
bottom: '0px',
left: '0px',
};
return (
<div className="banner-container settings-banner">
<table className="settings-banner-container">
<tbody>
<tr className="setttings-container-tr">
<div
className="xx"
style={{ backgroundColor: this.state.background }}>
<div className="title-cell-value settings-banner-title">
Brand color
</div>
<div>
<Button onClick={this.handleClick}>Pick Color</Button>
{this.state.displayColorPicker ? (
<div style={popover}>
<div
style={cover}
onClick={this.handleClose}
onKeyDown={this.handleClick}
role="button"
tabIndex="0"
aria-label="Save"
/>
<ChromePicker
color={this.state.background}
onChange={this.handleChange}
onChangeComplete={this.handleChangeComplete}
/>
</div>
) : null}
</div>
</div>
</tr>
</tbody>
</table>
</div>
);
}
}
In the above file, the ChromePicker is used to choose a color and save its value in this.state.background. I'm using that value to update the color of div with class xx. This works good, the div's color is updated directly.
However, I don't know how to "export" that color value outside and use it in another component.
In this case it would be the Toolbar, I want to send the value from this.state.background to the style = {{ .. }}
Is there a way to do it?
import React from 'react';
import Logo from '../Logo/Logo';
export default class Toolbar extends React.PureComponent {
render() {
return (
<div className="corporate-toolbar" style={{ backgroundColor: 'green' }}>
<Logo corporate />
</div>
);
}
}
There is many ways to do it
You can use context(best solution), redux(if you app is really big) or just move the property to the common parent and pass it to components (it's the worst way, not recommended)
Documentation for context - https://reactjs.org/docs/context.html
Documentation for redux - https://react-redux.js.org
A simple example of using context https://www.digitalocean.com/community/tutorials/react-usecontext
Here is a working example using context:
//in file ColorContext.js (should export but breaks snippet)
const ColorContext = React.createContext();
const ColorProvider = ({ children }) => {
const [color, setColor] = React.useState('#fff');
return (
<ColorContext.Provider value={{ color, setColor }}>
{children}
</ColorContext.Provider>
);
};
//in file Banner.js
class Banner extends React.PureComponent {
handleChange = (color) => {
this.context.setColor(color);
};
render() {
return (
<div style={{ backgroundColor: this.context.color }}>
<select
value={this.context.color}
onChange={(e) =>
this.handleChange(e.target.value)
}
>
<option value="#fff">fff</option>
<option value="#f00">f00</option>
<option value="#f0f">f0f</option>
</select>
</div>
);
}
}
//ColorContext is imported from ColorContext.js
Banner.contextType = ColorContext;
//in file Toolbar.js
class Toolbar extends React.PureComponent {
render() {
return (
<h1 style={{ backgroundColor: this.context.color }}>
Toolbar
</h1>
);
}
}
//ColorContext is imported from ColorContext.js
Toolbar.contextType = ColorContext;
const App = () => (
<div>
<Banner />
<Toolbar />
</div>
);
ReactDOM.render(
<ColorProvider>
<App />
</ColorProvider>,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>

CSS in JS, how to make props.className the priority class

We need components where the class passed as props should have more priority than the default class.
When passing classes as a prop, the component gives priority to the
class created in his own file.
Text.jsx
// this will be a component in another folder, it will be used in the whole app so it
// should haveDYNAMIC styling
function Text(props) {
const useStyles = makeStyles(theme => ({
default: {
fontSize: 18,
color: "black"
}
}));
const classes = useStyles();
return (
<div className={classNames(classes.default, props.className)}>
{props.children}
</div>
);
}
App.jsx
function App() {
const useStyles = makeStyles(theme => ({
title: {
fontSize: 80,
color: "red"
},
notGoodPractice: {
fontSize: "80px !important"
}
}));
const classes = useStyles();
return (
<div className="App">
<Text className={classes.title}>Text in here is 18px</Text>
<Text className={classes.notGoodPractice}>
Text in here is 80px
</Text>
</div>
);
}
React Snippet => CodeSandBox
You can prioritise classes passed as props this way.
Just make sure you don't apply makeStyles on it so that you can access them correctly in child.
import React from "react";
import ReactDOM from "react-dom";
import { makeStyles } from "#material-ui/core/styles";
// this is how we will use the Text component
function App() {
const style = {
title: {
fontSize: "80px",
color: "red",
"#media (max-width: 767px)": {
color: "green"
}
},
notGoodPractice: {
fontSize: "80px"
}
};
return (
<div className="App">
<Text class1={style.title}>Title should be with size 80px</Text>
<Text class1={style.notGoodPractice}>Title should be with size 80px</Text>
</div>
);
}
// this will be a component in another folder, it will be used throw the in app so it should be as DYNAMIC as possible
function Text(props) {
const useStyles = makeStyles(theme => ({
default1: {
fontSize: 18,
color: "black"
},
priorityClass: props => props.class1
}));
const { default1, priorityClass } = useStyles(props);
return <div className={`${default1} ${priorityClass}`}>{props.children}</div>;
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Check out live sandbox https://codesandbox.io/s/zen-voice-mb60t

How to render post in different layout getting from same parent component in reactjs

I am trying to render posts with different style in the same child component something like this.
I am getting posts from wordpress api in home component then passed to renderedPost component where posts are being maped and then passed to PostPreview where it is being displayed. Here i want to display posts like i have provided in the above picture.
This is my code .
src/views/home.js
import React, { Component } from 'react';
import Layout from '../layouts';
import { connect } from 'react-redux';
import { fetchPosts } from '../actions/postActions';
import PropTypes from 'prop-types';
import RenderPost from '../components/RenderPost';
class Home extends Component {
componentWillMount() {
this.props.fetchPosts();
}
render() {
console.log(this.props.posts)
return (
<Layout>
{this.props.posts && <RenderPost posts={this.props.posts}/>}
</Layout>
);
}
}
Home.prototypes = {
fetchPosts: PropTypes.func.isRequired,
posts: PropTypes.array.isRequired
}
const mapStateToProps = state => ({
posts: state.posts.items,
})
export default connect(mapStateToProps, {fetchPosts})(Home);
src/component/renderedPost.js
import React from 'react'
import PostPreview from './PostPreview';
export default function RenderPost(props) {
console.log(props);
return (
<>
{props.posts.map(post => <PostPreview
title={post.title.rendered}
key={post.id}
image={post.imageURL}
/>)}
</>
)
}
component/PostsPreview.js // now here i am confused how to render posts like in the above picture.
import React from 'react'
export default function PostPreview({title}) {
return (
<div>
<h1>{title}</h1>
</div>
)
}
You could set display to flex on the post container, and add a new prop called e.g. imageLeft that you set to true for every other post and use that to alternative the flex-direction between row and row-reverse to alternate the image position.
Example
class Home extends React.Component {
state = {
posts: [
{ id: 0, title: "foo", imageURL: "https://placekitten.com/200/200" },
{ id: 1, title: "bar", imageURL: "https://placekitten.com/200/200" },
{ id: 2, title: "baz", imageURL: "https://placekitten.com/200/200" }
]
};
render() {
return (
<div>
<RenderPost posts={this.state.posts} />
</div>
);
}
}
function RenderPost(props) {
return (
<div>
{props.posts.map((post, index) => (
<PostPreview
key={post.id}
imageLeft={index % 2 === 0}
title={post.title}
image={post.imageURL}
/>
))}
</div>
);
}
function PostPreview({ image, imageLeft, title }) {
return (
<div
style={{
display: "flex",
width: 200,
flexDirection: imageLeft ? "row" : "row-reverse"
}}
>
<div
style={{
backgroundImage: `url(${image})`,
backgroundSize: "cover",
flexGrow: 1
}}
/>
<h1>{title}</h1>
</div>
);
}
ReactDOM.render(<Home />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>

Chart won't render upon state change

I am testing out react-native and I am trying to make a simple lineChart which redraws on props change. I have a parent component HomeScreen which passes an array of integers as props to the LineChart child component. However, the LineChart is never drawn.
I have tried passing in an already initialized array with dummy values. The lineChart child component will then render, but it won't re-render on subsequent state changes.
I have checked the actual values of state and props in react-devtools, and the childcomponent does receive the props and the state is updated. How can I make the chart render the props I pass it?
UPDATE: So I took the advice from the replies here, and made the component functional. The chart now renders, but there is still something wrong with the prop type. I'll investigate further and read up on the react-native-svg documentation. Thanks!
enter code here
import React from 'react';
import { View } from 'react-native';
import { LineChart, Grid } from 'react-native-svg-charts'
const BeatChart = ({ data }) => (
<LineChart
style={{ height: 200 }}
data={data}
svg={{ stroke: 'rgb(0, 255, 255)' }}
contentInset={{ top: 20, bottom: 20 }}
>
<Grid />
</LineChart>
);
export default BeatChart;
You don't need state in this example, so you could just use the functional component.
import React from 'react';
import { View } from 'react-native';
import { LineChart, Grid } from 'react-native-svg-charts'
const BeatChart = ({ data }) => (
<LineChart
style={{ height: 200 }}
data={data}
svg={{ stroke: 'rgb(0, 255, 255)' }}
contentInset={{ top: 20, bottom: 20 }}
>
<Grid />
</LineChart>
);
export default BeatChart;
since the render occurs on every change in props, you can comment this part of the code.
static getDerivedStateFromProps(nextProps, prevState) {
if (nextProps.data !== prevState.data) {
return { data: nextProps.data };
}
return null;
}
even if you want to implement it, use componentWillmount if needed.
otherwise the code works fine.
so your final code be like:
import React from 'react';
import { View } from 'react-native';
import { LineChart, Grid } from 'react-native-svg-charts'
class BeatChart extends React.PureComponent {
constructor(props) {
super(props)
this.state = {
data: [],//your data
}
};
// static getDerivedStateFromProps(nextProps, prevState) {
// if (nextProps.data != prevState.data) {
// return { this.setState({data: nextProps.data}) };
// }
// return null;
// }
render() {
const arr = this.state.data;
return (
<LineChart
style={{ height: 200 }}
data={arr}
svg={{ stroke: 'rgb(0, 255, 255)' }}
contentInset={{ top: 20, bottom: 20 }}
>
<Grid />
</LineChart>
)
}
}
export default BeatChart;

React Native changing background color according to data that comes through http request from server

I am new at React Native.
I'm working on a code that will change the background color of a box (card) according to the data that I will get from API. I want to check first if the title is like 'Taylor' make background red , if it is 'Fearless' make it green and so on.
Here is the API that I got information from :
http://rallycoding.herokuapp.com/api/music_albums
This is the code divided into several files.
First of them index.js
// Import a library to help to create a component
import React from 'react';
import { Text, AppRegistry, View } from 'react-native';
import Header from './src/components/header.js';
import AlbumList from './src/components/AlbumList.js'
// create a component
const App = () => (
<View>
<Header headerText={'Smart Parking'}/>
<AlbumList />
</View>
);
//render it to the device
AppRegistry.registerComponent('albums2', () => App);
second is AlbumList.js
import React, { Component } from 'react';
import { View } from 'react-native';
import axios from 'axios';
import AlbumDetail from './AlbumDetail.js'
class AlbumList extends Component {
state = { albums: [] };
componentWillMount() {
axios.get('https://rallycoding.herokuapp.com/api/music_albums')
.then(response => this.setState({ albums: response.data }) );
}
renderAlbums() {
return this.state.albums.map(album =>
<AlbumDetail key={album.title} album={album} />
);
}
render() {
return(
<View>
{this.renderAlbums()}
</View>
);
}
}
export default AlbumList;
3rd is AlbumDetail.js
import React from 'react';
import {Text, View} from 'react-native';
import Card from './Card.js'
const AlbumDetail = (props) => {
return(
<Card>
<Text> {props.album.title} </Text>
</Card>
);
};
export default AlbumDetail;
4th is card which I need to change background of it
import React from 'react';
import { View } from 'react-native';
const Card = (props) => {
return (
<View style={styles.containerStyle}>
{props.children}
</View>
);
};
const styles = {
containerStyle:{
borderWidth: 1,
borderRadius: 2,
backgroundColor: '#ddd',
borderBottomWidth: 0,
shadowColor: '#000',
shadowOffset: {width: 0, height:2 },
shadowOpacity: 0.1,
shadowRadius: 2,
elevation: 1,
marginLeft: 5,
marginRight: 5,
marginTop: 10
}
};
export default Card;
last one is header
// Import libraries for making components
import React from 'react';
import { Text, View } from 'react-native';
// make a components
const Header = (props) => {
const { textStyle, viewStyle } = styles;
return(
<View style={viewStyle}>
<Text style={textStyle}>{props.headerText}</Text>
</View>
)
};
const styles ={
viewStyle:{
backgroundColor:'orange',
justifyContent: 'center',
alignItems: 'center',
height: 60,
},
textStyle: {
fontSize: 20
}
};
// make the component to the other part of the app
export default Header;
Basically you need to pass the title of the album as prop to the Card from the AlbumDetails component and then on each Card calculate the color to use and pass it in the style like this:
// AlbumDetails.js component
import React from 'react';
import {Text, View} from 'react-native';
import Card from './Card.js'
const AlbumDetail = (props) => {
return(
<Card title={props.album.title}>
<Text> {props.album.title} </Text>
</Card>
);
};
export default AlbumDetail;
// Card.js component
import React from "react";
import { View } from "react-native";
function calculateColor(title) {
let bgColor;
switch (title) {
case "Taylor":
bgColor = "red";
break;
case "Fearless":
bgColor = "green";
break;
default:
bgColor = "orange";
break;
}
return bgColor;
}
const Card = props => {
const { title } = props;
const backgroundColor = calculateColor(title);
return (
<View style={[styles.containerStyle, { backgroundColor: backgroundColor }]}>
{props.children}
</View>
);
};
const styles = {
containerStyle: {
borderWidth: 1,
borderRadius: 2,
backgroundColor: "#ddd",
borderBottomWidth: 0,
shadowColor: "#000",
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 2,
elevation: 1,
marginLeft: 5,
marginRight: 5,
marginTop: 10
}
};
export default Card;
Something like this should work:
Change the AlbumDetail to conditionally render the Card.
const AlbumDetail = props => {
if (props.album.title === 'Taylor') {
return (
<Card style={{ backgroundColor: 'red' }}>
<Text>{props.album.title}</Text>
</Card>
);
} else {
return (
<Card style={{ backgroundColor: 'green' }}>
<Text>{props.album.title}</Text>
</Card>
);
}
};
Override the default style of the card using the passed style prop.
const Card = props => {
return (
<View style={[styles.containerStyle, props.style]}>{props.children}</View>
);
};
accepted answer is great just its a bad habit to do things in render.
i also not sure since every title has a color why wouldnt the server send this in the object props in first place ? :)
class AlbumList extends Component {
state = { albums: [] };
componentDidMount() {
axios.get('https://rallycoding.herokuapp.com/api/music_albums')
.then(response=> Array.isArray(response.data) ? response.data : []) // alittle validation would not hurt :) !
.then(data => this.setState({ albums: data }) );
}
selectHeaderColorForAlbum( album ){
let headerColor = 'red';
// switch(album.title){ ..you logic }
return headerColor;
}
renderAlbums() {
return this.state.albums.map(album =>
<AlbumDetail key={album.title} album={album} color={this.selectHeaderColorForAlbum(album)} />
);
}
render() {
return(
<View>
{this.renderAlbums()}
</View>
);
}
}
const Card = (props) => {
return (
<View style={[styles.containerStyle,{color:props.headerColor}]}>
{props.children}
</View>
);
};
this is easier your logic will render only once.
also notice that react >16.0 depricated componentWillMount, so use DidMount

Categories

Resources