React-motion with redux - reactjs

I am trying to animate adding a new comment in my React + Redux app with react-motion.
class Comments extends Component {
getDefaultStyles() {
const { comments } = this.props;
return comments.map((c, i) => {
return {
key: "" + i,
style: { top: -50, opacity: 0.2 },
data: c
}
});
}
getStyles() {
const { comments } = this.props;
return comments.map((c, i) => {
return {
key: "" + i,
style: {
top: spring(0, presets.gentle),
opacity: spring(1, presets.gentle)
},
data: c
}
})
}
willEnter() {
return { top: -50, opacity: 0.2 }
}
render() {
let { comments } = this.props;
return (
<div>
<TransitionMotion defaultStyles={this.getDefaultStyles()} styles={this.getStyles()} willEnter={this.willEnter}>
{styles =>
<div>
{
styles.map((c) => {
return (
<Comment key={c.key} comment={c.data} style={{...c.style, overflow: 'hidden'}} />
)
})
}
</div>
}
</TransitionMotion>
</div>
)
}
}
Then the style is passed to the first div in Comment component.
While loading the comments the animation is OK. But user add a comment, and then the fetchComments method is called to fetch all the comments, the animation does not occur. Is this something to do with redux? I am passing my comment using mapStateToProps and connect.

The problem was with the key. The animation was occuring, but at the bottom of the comments, as mapping through them assigned them a key based on index in the array. When I changed the key to contain comment.id number it started working properly!

Related

React Native Dynamic View Mapped from Array Does Not Update When Element Changes

I have a view in which I am dynamically adding Input components from React Native Elements. Ultimately, I need to validate the text typed in Input, and so, for now, I am trying to change the errorMessage prop from false to true upon onChangeText. Unfortunately, nothing I try changes the errorMessage even though the state component changes to true. I have a Snack, and, for convenience, my code follows:
import * as React from 'react'
import { ScrollView, StyleSheet, View } from 'react-native'
import { Button, Icon, Input, Text } from 'react-native-elements'
import * as Shortid from 'shortid'
export default class App extends React.Component {
constructor (props) {
super(props)
this.state = {
timeInputs: [],
validities: []
}
this.addTimeInput = this.addTimeInput.bind(this)
this.removeTimeInput = this.removeTimeInput.bind(this)
this.mutateValidities = this.mutateValidities.bind(this)
}
componentDidMount () {
this.addTimeInput()
}
addTimeInput () {
const identifier = Shortid.generate()
const timeInputs = this.state.timeInputs
const validities = this.state.validities
let isTimeValid = false
let time = ''
new Promise(
(resolve, reject) => {
resolve(
validities.push(
{ id: identifier, value: isTimeValid }
),
timeInputs.push(
<View key = { identifier }>
<View style = { styles.row }>
<Input
errorMessage = {
this.state.validities.filter(
validity => validity.id !== identifier
).value == true
? 'Valid'
: 'Invalid'
}
errorStyle = { styles.error }
onChangeText = {
value => {
time = value
this.mutateValidities(identifier, true)
console.log('TIME ' + identifier + ': ' + time)
}
}
placeholder = 'HH:MM AM/PM'
ref = { React.createRef() }
/>
<Icon
color = { colors.dark }
name = 'add-circle'
onPress = { () => this.addTimeInput() }
type = 'material'
/>
<Icon
color = { colors.dark }
name = 'remove-circle'
onPress = {
() => {
if (this.state.timeInputs.length > 1) {
this.removeTimeInput(identifier)
} else {
console.log('LENGTH: ' + this.state.timeInputs.length)
}
}
}
type = 'material'
/>
</View>
</View>
)
)
}
)
.then(
this.setState(
{
timeInputs: timeInputs,
validities: validities
}
)
)
.catch(
(reason) => {
console.log(
'Failed to create time-input because of the following: ' + reason
)
}
)
}
mutateValidities (key, value) {
this.setState(
{
validities: this.state.validities.map(
validity => validity.id === key
? {...validity, value: value}
: validity
)
}
)
}
removeTimeInput (key) {
this.setState(
{
timeInputs: this.state.timeInputs.filter(
timeInput => timeInput.key !== key
),
validities: this.state.validities.filter(
validity => validity.id !== key
)
}
)
}
render () {
return (
<ScrollView contentContainerStyle = { styles.container }>
<Text h4 style = { styles.title }>Time Inputs</Text>
{
this.state.timeInputs.map(
(value) => { return value }
)
}
<Button
buttonStyle = { styles.button }
onPress = {
() => this.state.validities.map(
validity => console.log(validity.id + validity.value)
)
}
title = 'Log Validities'
/>
</ScrollView>
)
}
}
const colors = {
dark: 'steelblue',
light: 'aliceblue',
medium: 'lightsteelblue',
error: 'firebrick'
}
const styles = StyleSheet.create(
{
button: {
backgroundColor: colors.dark,
margin: 5
},
container: {
alignItems: 'center',
backgroundColor: colors.light,
flex: 1,
justifyContent: 'center'
},
error: {
color: colors.error,
fontSize: 12,
margin: 5
},
row: {
alignItems: 'center',
flexDirection: 'row',
margin: 5,
width: '80%'
},
title: {
margin: 5
}
}
)
Due credit goes to McGregor (2017) for getting me this far, but I am still stuck.
Reference:
McGregor, L. (2017, October 2) Whats the best way to update an object in an array in ReactJS? [Stack Overflow answer]. Retrieved from https://stackoverflow.com/a/46518653/6084947
I believe my problem was that I was trying to trigger changes in the view that were too deeply nested. Even assuming the props were passed correctly, the view would not have updated when the state changed because React only compares props and state so far. Following the recommendation made in "The Power Of Not Mutating Data" (Facebook, 2019), I avoided these issues with shallow comparison by making the text-input a full React component. I also applied React Redux to manage the state in a central store instead of passing props back and forth, which I never could get to work even after abstracting the text-input.
The code is now spread out between too many different files to post here, but anyone interested can view it on GitHub or Snack.
Reference:
Facebook. (2019). Optimizing Performance [Documentation]. Retrieved from https://reactjs.org/docs/optimizing-performance.html#the-power-of-not-mutating-data

Changing styles when scrolling React

I want to add the scrolling effect. At the start, the elements have the opacity: 0.2 property. When element is reached in the browser window, it is to replace the property with opacity: 1. At this moment, when I scroll, all elements change the property to opacity: 1. How to make this value when element is reached in the browser, the rest of the elements have the property opacity: 0.2
class QuestionListItem extends Component {
constructor() {
super();
this.state = {
opacity: 0.2,
};
}
componentDidMount = () => {
window.addEventListener('scroll', () => {
this.setState({
opacity: 1,
});
});
};
render() {
const { question } = this.props;
const { opacity } = this.state;
return (
<div>
<li
key={question.id}
className="Test__questions-item"
style={{ opacity: `${opacity}` }}
ref={
(listener) => { this.listener = listener; }
}
>
<p>
{question.question}
</p>
<QuestionAnswerForm />
</li>
</div>
);
}
}
I want effect like this https://anemone.typeform.com/to/jgsLNG
A proper solution could look like this. Of course, this is just a concept. You can fine-tune the activation/deactivation logic using props from getBoundingClientRect other than top (e.g. height, bottom etc).
Important that you should not set the component's state on every single scroll event.
const activeFromPx = 20;
const activeToPx = 100;
class ScrollItem extends React.Component {
state = {
isActive: false
}
componentDidMount = () => {
window.addEventListener('scroll', this.handleScroll);
this.handleScroll();
};
handleScroll = () => {
const { top } = this.wrapRef.getBoundingClientRect();
if (top > activeFromPx && top < activeToPx && !this.state.isActive) {
this.setState({ isActive: true });
}
if ((top <= activeFromPx || top >= activeToPx) && this.state.isActive) {
this.setState({ isActive: false });
}
}
setWrapRef = ref => {
this.wrapRef = ref;
}
render() {
const { isActive } = this.state;
return (
<div
className={`scroll-item ${isActive && 'scroll-item--active'}`}
ref={this.setWrapRef}
>
{this.props.children}
</div>
)
}
}
class ScrollExample extends React.Component {
render() {
return (
<div className="scroll-wrap">
<ScrollItem>foo</ScrollItem>
<ScrollItem>bar</ScrollItem>
<ScrollItem>eh</ScrollItem>
</div>);
}
}
ReactDOM.render(<ScrollExample />, document.getElementById('root'))
.scroll-wrap {
height: 300vh;
background: lightgray;
padding-top: 55px;
}
.scroll-item {
height: 60vh;
background: lightcyan;
margin: 10px;
opacity: 0.2;
}
.scroll-item--active {
opacity: 1;
}
<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>
You can include an isInViewport-like implementation as this one: https://gist.github.com/davidtheclark/5515733 then use it on your component.
componentDidMount = () => {
window.addEventListener('scroll', (event) => {
if (isElementInViewport(event.target) {
this.setState({
opacity: 1,
});
}
});
};
There's also read-to-use react-addons for this: https://github.com/roderickhsiao/react-in-viewport

ReactJS simple hover works critical slow

Here's whole class . This example works. No error in ts compiler no errors in browser logs .
import * as React from "react";
import { Label } from "../../components/label/label";
import IApp from "../../globals/interfaces";
import { Tap } from "../../globals/types";
import Services from "../../services/services";
import { HeaderI, HeaderStateI } from "./interface";
import { getMenuStyle, getMyStyle } from "./style";
export class Header extends React.Component<HeaderI, HeaderStateI, any> {
public add = Services.addElement;
private myRef: React.RefObject<HTMLDivElement>;
private myDOM: Element | Text;
constructor(args: any) {
super(args);
this.state = {
enabledComponent: true,
visibility: true,
debugView: false,
elements: [],
myStyle: getMyStyle(),
menuStyle: getMenuStyle(),
menuItemStyle: [getMenuStyle(), getMenuStyle()],
menuIsOpen: false,
myEvent: null,
};
this.myRef = React.createRef();
this.add = this.add.bind(this);
}
// Override func
public componentDidMount() {
this.myDOM = this.myRef.current;
}
public render() {
if ( this.state.visibility === true ) {
return (
<div ref={this.myRef} style={this.state.myStyle} >
<Label myStyle={this.state.menuStyle}
name="headerName"
text="MENU"
onClick={this.clickEvent.bind(this)}
onMouseEnterHandler={this.hoverIn.bind(this)}
onMouseLeaveHandler={this.hoverOut.bind(this)} />
{this.state.elements.map((element: React.ReactElement<any>, index) => {
return <span ref={this.myRef} key={index} style={this.state.menuItemStyle[index]}
onClick={this.clickMenuItem.bind(this)}>{element}</span>;
})}
</div>
);
}
}
// Override func
public componentDidUpdate(prevProps: any, prevState: any) {
// Typical usage (don't forget to compare props):
}
// Override func
public componentWillUpdate(nextProps: any, nextState: any) {
// We should not call setState !
// if (nextState.open == true && this.state.open == false) {
// this.props.onWillOpen();
// }
}
private adaptCss(e: CustomEvent) {
// DEMO for css changes :
// Collect (this of class instance)
const self = e.detail.data.self;
// Make any changes in css
// Collect base or initial css
const myStyle = getMyStyle();
// Make changes
myStyle.background = "yellow";
// Setup state and nothing more
self.setState({
myStyle,
});
}
private printMe() {
// console.log("Layout Header is active and update is on");
}
private clickEvent(event: MouseEvent | TouchEvent) {
if (this.state.menuIsOpen === false) {
const myKey = "header.01";
const element1Args: IApp.NewElementArgsI = {
key: myKey,
onClick: null,
myStyle: null,
content: "HOME",
hoverIn: ((e) => this.hoverIn(e, myKey)),
hoverOut: ((e) => this.hoverOut(e, myKey)),
};
const myKey2 = "header.02";
const element2Args: IApp.NewElementArgsI = {
key: myKey2,
onClick: null,
myStyle: null,
content: "ABOUT",
hoverIn: ((e) => this.hoverIn(e, myKey2)),
hoverOut: ((e) => this.hoverOut(e, myKey2)),
};
this.add(element1Args);
this.add(element2Args);
// Set new state for menu
this.setState(
{menuIsOpen: !this.state.menuIsOpen},
);
} else {
// Menu is already visible , delete menu items
this.setState (
{
menuIsOpen: !this.state.menuIsOpen,
elements: [],
},
);
}
}
private clickMenuItem(event: MouseEvent | TouchEvent) {
const t = event.target as HTMLDivElement;
// Also possible to call event.target.textContent !
switch (t.textContent) {
case "HOME":
this.props.provide({instruction: "show_home"});
break;
case "ABOUT":
this.props.provide({instruction: "show_about"});
break;
default:
console.warn("No case for cleckMenuItem in bodyCOntent class!");
}
}
private hoverIn = (e: Tap, id: any) => {
const styleArrayCopy = JSON.parse(JSON.stringify(this.state.menuItemStyle));
this.state.elements.forEach((element: React.ReactElement<any>, index: number) => {
if (id === element.key) {
styleArrayCopy[index].color = "red";
} else {
styleArrayCopy[index].color = "initial";
}
});
if (this.state.elements.length === 0) {
const test = getMenuStyle();
test.color = "lime";
this.setState({
menuItemStyle: styleArrayCopy,
menuStyle: test,
});
} else {
this.setState({
menuItemStyle: styleArrayCopy,
});
}
}
private hoverOut = (e: Tap, id: any) => {
this.state.elements.forEach((element: React.ReactElement<any>, index: number) => {
if (id === element.key) {
const styleArrayCopy = JSON.parse(JSON.stringify(this.state.menuItemStyle));
styleArrayCopy[index].color = "initial";
this.setState({
menuItemStyle: styleArrayCopy,
});
}
});
}
}
I get style like that :
export function getMenuStyle(): IApp.MyMinimumCssInterface {
return {
display: "block",
background: "#445566",
height: "30px",
width: "100%",
textAlign: "center",
color: "inherits",
} as IApp.MyMinimumCssInterface;
}
On hover in and out i have ~400ms delay . If i moving up/down there is no hover effect. This is so bad. What will be when i add large assets add more code...
I detect very slow executing in not just this example even most simple example from reactJS tutorials ?!
I am also interested in React.ReactElement Object instance . Is it possible for OverRide some func - Like updateDid ?
To missunderstund from comment This is from React site :
The style attribute accepts a JavaScript object with camelCased
properties rather than a CSS string. This is consistent with the DOM
style JavaScript property, is more efficient, and prevents XSS
security holes. For example:
const divStyle = {
color: 'blue',
backgroundImage: 'url(' + imgUrl + ')',
};
I use it the same principle.
Updated , now looks like :
// Render
{this.state.elements.map((element: React.ReactElement<any>, index) => {
return <span ref={this.myRef} key={index} style={this.getStyle(element, index)} onClick={this.clickMenuItem.bind(this)}>{element}</span>;
})}
private hoverIn = (e: Tap, id: any) => {
const local: boolean[] = [];
this.state.elements.forEach((element: React.ReactElement<any>, index: number) => {
if (id === element.key) {
local.push(true);
} else {
local.push(false);
}
});
Any explanation ??
I finally found solution for very slow work flows.
There is no connections with React at all.
I have global.css who's loading on begin. First i noticed that only text delay.
I create text shadow and i most suspect on shadow but it was transition.
This code is most expensively code was :
-webkit-transition: color 300ms cubic-bezier(0.42, 0, 0.58, 1);
-moz-transition: color 300ms cubic-bezier(0.42, 0, 0.58, 1);
-o-transition: color 300ms cubic-bezier(0.42, 0, 0.58, 1);
transition: color 300ms cubic-bezier(0.42, 0, 0.58, 1);
I remove this part of code.
Maybe this answer will help somebody .

Stacking Cards in react native

Currently I am learning react native and I have some problem while I am making stack of the cards.
Here is my code:
constructor(props) {
super(props);
const position = new Animated.ValueXY();
const panResponder = new PanResponder.create({
onStartShouldSetPanResponder: () => true,
onPanResponderMove: (event, gesture) => {
position.setValue({ x: gesture.dx, y: gesture.dy })
},
});
this.state = { panResponder, position, index: 0 };
}
renderCards() {
if(this.state.index >= this.props.data.length) {
return this.props.renderNoMoreCard();
}
return this.props.data.map((item, i) => {
if( i < this.state.index) { return null}
if(i === this.state.index) {
return (
<Animated.View
key={item.id}
style={[ styles.cardStyle, this.getCardStyle()]}
{...this.state.panResponder.panHandlers}
>
{this.props.renderCard(item)}
</Animated.View>
);
}
return (
<Animated.View key={item.id} style={styles.cardStyle}>
{this.props.renderCard(item)}
</Animated.View>
);
}).reverse();
}
render() {
return(
<View>
{this.renderCards()}
</View>
);
}
}
const styles = {
cardStyle: {
position: 'absolute',
width: SCREEN_WIDTH,
top: 0,
}
};
export default Deck;
The title card 2 is showing instead of card 1 but when I swipe the card. Card 1 is removed from view and title is changed to 3.
The mistake was that while using PanResponder which is use to reconciles several touches into a single gesture. So,
I was declaring a object const panResponder = new PanResponder.create
but the code should be
const panResponder = PanResponder.create and by Removing this single word "new" it worked!

Redux state shape for managing multiple React component instances?

Working on a small project using React and Redux in which I'm making what is essentially a Trello clone, or kanban system. But I'm having trouble figuring out how to construct my state for Redux so that things don't get weird.
Essentially, a user needs to be able to create multiple instances of a <Board/> component via React. Each <Board/> instance has a title. Continuing to drill down, each </Board> instance can also have an array of its own <List/> component instances. Each <List/> instance can in turn have its own <Card/> component instances.
Which is where I get confused. In React, it's simple--each instance of <Board/> and each instance of <List/> just manage their own state. But I can't figure out how to refactor everything so that Redux manages all state, but each component instance receives the correct slice of state.
So far, I've constructed my Redux state to look as follows. Any help is appreciated!
{
boards: [
{
title: 'Home',
lists: [
{
title: 'To Do',
cards: [
{ title: 'Finish this project.'},
{ title: 'Start that project.'}
]
},
{
title: 'Doing',
cards: []
},
{
title: 'Done',
cards: []
}
]
}
]
}
redux is basically a one global store object. so theoretically this is no different than using react without redux but keeping the store at the most top level component's state.
Of course with redux we gain a lot of other goodies that makes it a great state manager. But for the sake of simplicity lets focus on the state structure and data flow between the react components.
Lets agree that if we have one global store to hold our single source of truth then we don't need to keep any local state inside our child components.
But we do need to break and assemble our data within our react flow, so a nice pattern is to create little bits of components that just get the relevant data an id and handlers so they can send back data to the parents with the corresponding id. This way the parent can tell which instance was the one invoking the handler.
So we can have a <Board /> that renders a <List /> that renders some <Cards /> and each instance will have it's own id and will get the data it needs.
Lets say we want to support addCard and toggleCard actions, We will need to update our store in couple level for this.
For toggling a card we will need to know:
What is the Card id that we just clicked on
What is the List id that this card belongs to
What is the Board id that this list is belong to
For adding a card we will need to know:
What is the List id that we clicked on
What is the Board id that this list is belong to
Seems like the same pattern but with different levels.
To do that we will need to pass onClick events to each component and this component will invoke it while passing it's own id to the parent, in turn the parrent will invoke it's onClick event while passing the child's id and it's own id so the next parent will know which child instances were being clicked.
For example:
Card will invoke:
this.props.onClick(this.props.id)
List will listen and will invoke:
onCardClick = cardId => this.props.onClick(this.props.id,cardId);
Board wil llisten and will invoke:
onListClick = (listId, cardId) => this.props.onClick(this.props.id, listId, cardId)
Now our App can listen as well and by this time it will have all the necessary data it needs to perform the update:
onCardToggle(boardId, listId, cardId) => dispatchToggleCard({boardId, listId, cardId})
From here its up to the reducers to do their job.
See how the components transfer data upwards, each component gather the data sent from its child and passing it upwards while adding another piece of data of itself. Small bits of data are assembled up until the top most component get all the data it needs to perform the updates to the state.
I've made a small example with your scenario, note that i'm not using redux due to the limitations of stack-snippets. I did wrote however the reducers and the entire logic of the updates and data flow, but i skipped the action creators part and connecting to an actual redux store.
I think it can give you some idea on how to structure your store, reducers and components.
function uuidv4() {
return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c =>
(c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
)
}
class Card extends React.Component {
onClick = () => {
const { onClick, id } = this.props;
onClick(id);
}
render() {
const { title, active = false } = this.props;
const activeCss = active ? 'active' : '';
return (
<div className={`card ${activeCss}`} onClick={this.onClick}>
<h5>{title}</h5>
</div>
);
}
}
class List extends React.Component {
handleClick = () => {
const { onClick, id } = this.props;
onClick(id);
}
onCardClick = cardId => {
const { onCardClick, id: listId } = this.props;
onCardClick({ listId, cardId });
}
render() {
const { title, cards } = this.props;
return (
<div className="list">
<button className="add-card" onClick={this.handleClick}>+</button>
<h4>{title}</h4>
<div>
{
cards.map((card, idx) => {
return (
<Card key={idx} {...card} onClick={this.onCardClick} />
)
})
}
</div>
</div>
);
}
}
class Board extends React.Component {
onAddCard = listId => {
const { onAddCard, id: boardId } = this.props;
const action = {
boardId,
listId
}
onAddCard(action)
}
onCardClick = ({ listId, cardId }) => {
const { onCardClick, id: boardId } = this.props;
const action = {
boardId,
listId,
cardId
}
onCardClick(action)
}
render() {
const { title, list } = this.props;
return (
<div className="board">
<h3>{title}</h3>
{
list.map((items, idx) => {
return (
<List onClick={this.onAddCard} onCardClick={this.onCardClick} key={idx} {...items} />
)
})
}
</div>
);
}
}
const cardRedcer = (state = {}, action) => {
switch (action.type) {
case 'ADD_CARD': {
const { cardId } = action;
return { title: 'new card...', id: cardId }
}
case 'TOGGLE_CARD': {
return {
...state,
active: !state.active
}
}
default:
return state;
}
}
const cardsRedcer = (state = [], action) => {
switch (action.type) {
case 'ADD_CARD':
return [...state, cardRedcer(null, action)];
case 'TOGGLE_CARD': {
return state.map(card => {
if (card.id !== action.cardId) return card;
return cardRedcer(card, action);
});
}
default:
return state;
}
}
const listReducer = (state = [], action) => {
switch (action.type) {
case 'ADD_CARD': {
const { listId } = action;
return state.map(item => {
if (item.id !== listId) return item;
return {
...item,
cards: cardsRedcer(item.cards, action)
}
});
}
case 'TOGGLE_CARD': {
const { listId, cardId } = action;
return state.map(item => {
if (item.id !== listId) return item;
return {
...item,
cards: cardsRedcer(item.cards,action)
}
});
}
default:
return state;
}
}
class App extends React.Component {
state = {
boards: [
{
id: 1,
title: 'Home',
list: [
{
id: 111,
title: 'To Do',
cards: [
{ title: 'Finish this project.', id: 1 },
{ title: 'Start that project.', id: 2 }
]
},
{
id: 222,
title: 'Doing',
cards: [
{ title: 'Finish Another project.', id: 1 },
{ title: 'Ask on StackOverflow.', id: 2 }]
},
{
id: 333,
title: 'Done',
cards: []
}
]
}
]
}
onAddCard = ({ boardId, listId }) => {
const cardId = uuidv4();
this.setState(prev => {
const nextState = prev.boards.map(board => {
if (board.id !== boardId) return board;
return {
...board,
list: listReducer(board.list, { type: 'ADD_CARD', listId, cardId })
}
})
return {
...prev,
boards: nextState
}
});
}
onCardClick = ({ boardId, listId, cardId }) => {
this.setState(prev => {
const nextState = prev.boards.map(board => {
if (board.id !== boardId) return board;
return {
...board,
list: listReducer(board.list, { type: 'TOGGLE_CARD', listId, cardId })
}
})
return {
...prev,
boards: nextState
}
});
}
render() {
const { boards } = this.state;
return (
<div className="board-sheet">
{
boards.map((board, idx) => (
<Board
id={board.id}
key={idx}
list={board.list}
title={board.title}
onAddCard={this.onAddCard}
onCardClick={this.onCardClick}
/>
))
}
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
.board-sheet{
padding: 5px;
}
.board{
padding: 10px;
margin: 10px;
border: 1px solid #333;
}
.list{
border: 1px solid #333;
padding: 10px;
margin: 5px;
}
.card{
cursor: pointer;
display: inline-block;
overflow: hidden;
padding: 5px;
margin: 5px;
width: 100px;
height: 100px;
box-shadow: 0 0 2px 1px #333;
}
.card.active{
background-color: green;
color: #fff;
}
.add-card{
cursor: pointer;
float: right;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

Resources