I found the child component Element was not connected when I want to use action in child component.
how to connect it ?
code:
import { connect } from 'react-redux';
import * as actions from '../actions';
class Element extends React.Component {
constructor(props) {
super(props);
}
render() {
let { children } = props.el.children;
return (
<div>
{ children ?
children.map(el =>
<Element key={ 'el-' + el.id } el={ el } />
)
:
null
}
</div>
)
}
}
Element = connect(
null
,
actions
)(Element);
export default Element;
You are rendering <Elemnt /> inside it's own render function.
If you just want to pass the children down the render function of your Element component then just change it to this:
import { connect } from 'react-redux';
import * as actions from '../actions';
class Element extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
{ this.props.children }
</div>
)
}
}
Element = connect(
null
,
actions
)(Element);
export default Element;
Note that the wrapper <div> is there because current version of react only allow one top level element in the render body, and this.props.children can hold more than one element.
Related
I'm working with treebeard in my react project.
when I try to add a user-defined style it's not getting applied to the container.
I have tried different methods to achieve this.
I tried to define the style from tag, tried to define style.css in a different file, import it and assign it to style in Treedeard tag.
the main goal is to change the background color and the position.
Here is my code:
workspace.jsx
import React from "react";
import {Treebeard} from 'react-treebeard';
import data from "./data";
export class WorkSpace extends React. Component {
constructor(props){
super(props);
this.state = {
data: {data}
};
this.onToggle = this.onToggle.bind(this);
const decorators = {
Container: (props) => {
return (
<div style={props.backgroundColor="yellow"}>
</div>
);
}
};
}
onToggle(node, toggled){
const {cursor, data} = this.state.data;
if (cursor) {
this.setState(() => ({cursor, active: false}));
}
node.active = true;
if (node.children) {
node.toggled = toggled;
}
this.setState(() => ({cursor: node, data: Object.assign({}, data)}));
}
render() {
return (
<div className="base_container">
<h3>Select Component</h3>
<div className="components">
<Treebeard
data={data}
onToggle={this.onToggle}
style = {style_components}
decorators={this.decorators}
/>
</div>
</div>
);
}
}
I have a react component where I am trying to change the background color of the css when clicking the div.
I know you can set the color in the component, but I am using this component many times, and don't to make multiple component files with just a different color, and even if I did, I am curious besides the fact.
How can I access (or even console.log to figure it out on my own) the css file and its properties through the component? Thanks ahead of time.
If you want to keep all background-color styles in your .css/.scss file, you will need to have a good className strategy to link the styles to your components. Here is my suggestion:
styles.scss
.blue {
background-color: blue;
&.clicked {
background-color: red;
}
}
Container.js
import React from 'react';
import ClickableDiv from './ClickableDiv.js';
const Container = () => (
<ClickableDiv className="blue">
<p>This is my text.</p>
</ClickableDiv>
);
export default Container;
ClickableDiv.js
import React, { Component } from 'react';
class ClickableDiv extends Component {
constructor() {
super();
this.state = { clicked: false };
this.handleDivClick = this.handleDivClick.bind(this);
}
handleDivClick() {
this.setState({ clicked: true });
}
render() {
const divClassName = [this.props.classname];
if (this.state.clicked) divClassName.push('clicked');
return (
<div className={divClassName.join(' ').trim()} onClick={this.handleDivClick}>
{this.props.children}
</div>
);
}
}
export default ClickableDiv;
Rendered Markup
Unclicked:
<div class="blue"><p>This is my text.</p></div>
Clicked:
<div class="blue clicked"><p>This is my text.</p></div>
You can pass in the desired background color as a prop, and use internal state with an onClick handler.
Container.js
import React from 'react';
import ClickableDiv from './ClickableDiv';
const Container = () => (
<ClickableDiv backgroundColor="#FF0000">
<p>This is my text.</p>
</ClickableDiv>
);
export default Container;
ClickableDiv.js
import React, { Component } from 'react';
class ClickableDiv extends Component {
constructor() {
super();
this.state = {};
this.handleDivClick = this.handleDivClick.bind(this);
}
handleDivClick() {
const { backgroundColor } = this.props;
if (backgroundColor) this.setState({ backgroundColor });
}
render() {
const { backgroundColor } = this.state;
return (
<div style={{ backgroundColor }} onClick={this.handleDivClick}>
{this.props.children}
</div>
);
}
}
export default ClickableDiv;
Better to make an external css file and write your css code in that file and just import that one in index.html
I have the following react component that passed data to another component:
export default class App extends TrackerReact(Component){
getUserFrameData(){
return (FrameCollection.find().fetch());
}
render(){
return(
<div className="main-container">
<Frames
data={this.getUserFrameData()}
/>
</div>
);
}
}
Now I want my frames component to do an action when the component initialises.
export default class Frames extends Component{
componentDidMount(){
console.log(this.props.data);
}
render() {...}
}
But on I only get empty data at on loadup. I think it's because I'm using subscriptions and a login system. So how can I tell my Frames component to wait until everything is "loaded up"?
Use the ready method of the subscription object.
constructor() {
super();
this.state = {
sub: Meteor.subscribe('myPublication')
}
}
render() {
if (!this.state.sub.ready()) return <p>Loading...</p>;
return ...
}
http://docs.meteor.com/api/pubsub.html#Subscription-ready
I'm starting to implement the smart/dumb component pattern where the "dumb" component knows nothing about it's environment and receives all of it's data through props. What do you do when the dumb component has to submit or change data? How can it communicate with the outside world and still be "dumb"?
Here's my basic example I'm using to figure this pattern out. If I were to add and onClick event to the MyTask component that updated a counter in the DB, what would handle that event?
// components/MyList.jsx
import React from 'react';
export default class MyList extends React.Component {
render() {
return(
<div>
<h3>{this.props.listName}</h3>
<ul>
{this.props.tasks.map((task) => (
<MyTask key={task.id} task={task} />
))}
</ul>
</div>
);
}
}
MyList.propTypes = {
listName: React.PropTypes.string.isRequired,
tasks: React.PropTypes.array.isRequired,
}
export class MyTask extends React.Component {
render() {
return (
<li>{this.props.task.text}</li>
);
}
}
MyTask.propTypes = {
task: React.PropTypes.object.isRequired,
}
and the app:
// app.jsx
import React from 'react';
import MyList from './components/MyList.jsx'
export class TaskApp extends React.Component {
getList() {
return('Today Stuff');
}
getTasks() {
return([
{id: 1, text: 'foo'},
{id: 2, text: 'diggity'},
{id: 3, text: 'boo'},
{id: 4, text: 'bop'}
]);
}
render() {
return (
<MyList listName={this.getList()} tasks={this.getTasks()} />
);
}
}
Generally speaking you can handle this by passing function references from your 'smart' components down to your 'dumb' components. The dumb component then isn't responsible for implementing any of the logic associated with the function, just telling the smart component 'I've been clicked'.
In this case inside of your TaskApp class in app.jsx you could have your click handler:
//app.jsx
...
handleClick() {
// Update the DB counter by 1
}
...
render () {}
Then pass handleClick through your components as a prop:
<MyList listName={this.getList()} tasks={this.getTasks()} handleClick={this.handleClick} />
<MyTask key={task.id} task={task} handleClick={this.props.handleClick} />
And execute it in the MyTask component when a list element is clicked:
<li onClick={this.props.handleClick}>{this.props.task.text}</li>
Keep in mind that if the handleClick() function is making use of 'this' at all, you'll need to .bind(this) on your function reference when you pass it down (or bind it in the constructor / use ES6 fat arrow functions).
EDIT: For examples of the other ways to bind 'this', you could in the constructor of your class assign the bound function to your this.handleClick reference, so:
export default class TaskApp extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
...
...
}
Which allows you to use this.handleClick the way you would normally expect.
Or you could use ES6 fat arrow functions, which preserve the context of 'this' when they are called:
<MyList
listName={this.getList()}
tasks={this.getTasks()}
handleClick={() => this.handleClick} />
Assuming that TaskApp is the smart component and MyList is the dumb component, it should be something like
Smart Component
// app.jsx
import React from 'react';
import MyList from './components/MyList.jsx'
export class TaskApp extends React.Component {
getList() {
return('Today Stuff');
}
getTasks() {
return([
{id: 1, text: 'foo'},
{id: 2, text: 'diggity'},
{id: 3, text: 'boo'},
{id: 4, text: 'bop'}
]);
}
handleClick(task){
// update the db here
}
render() {
return (
<MyList listName={this.getList()} tasks={this.getTasks()}
onClick={this.handleClick}/>
);
}
}
Dumb Component
// components/MyList.jsx
import React from 'react';
export default class MyList extends React.Component {
render() {
return(
<div>
<h3>{this.props.listName}</h3>
<ul>
{this.props.tasks.map((task) => (
<MyTask onClick={() => this.props.onClick(task)}
key={task.id} task={task} />
))}
</ul>
</div>
);
}
}
MyList.propTypes = {
listName: React.PropTypes.string.isRequired,
tasks: React.PropTypes.array.isRequired,
}
export class MyTask extends React.Component {
render() {
return (
<li onClick={this.props.onClick}>{this.props.task.text}</li>
);
}
}
MyTask.propTypes = {
task: React.PropTypes.object.isRequired,
}
You can pass the event handler callback as a prop to MyTask:
<MyTask onClick={this.handleTaskClick.bind(this)} ... />
And then use it in MyTask:
<li onClick={this.props.onClick}>...</li>
See: https://facebook.github.io/react/docs/tutorial.html#callbacks-as-props
At which point in a React components life cycle can I get the components css properties which are set in a css file?
I've tried it in the render method and the componentDidMount method and neither assigned the css properties to the component.
export default class HomeArtist extends React.Component {
constructor(props){
super(props);
}
componentDidMount(){
let ImageStore = document.getElementsByClassName('home-artist-display');
console.log("ComponentDidMount: ", ImageStore);
}
render(){
var ImageStyle = {
backgroundImage: "url("+this.props.info.image+")"
};
return (
<div className="home-artist-display" style={ImageStyle}>
<Link to={"artist/" + this.props.info.id}>
<h3 className="home-artist-name">{this.props.info.name}</h3>
</Link>
</div>
)
}
}
I wrote a React library that exposes a size object (with width and height props) to components.
For your use case you could use it like so:
import SizeMe from 'react-sizeme'; // import me!
class HomeArtist extends React.Component {
...
render(){
// Size gets passed in as props!
const { width, height } = this.props.size;
var ImageStyle = {
backgroundImage: "url("+this.props.info.image+")"
};
return (
<div className="home-artist-display" style={ImageStyle}>
<Link to={"artist/" + this.props.info.id}>
<h3 className="home-artist-name">{this.props.info.name}</h3>
</Link>
</div>
)
}
}
// wrap your component export!
export default SizeMe()(HomeArtist);
--
You can find out full details at https://github.com/ctrlplusb/react-sizeme