Skip to content

Instantly share code, notes, and snippets.

@biglovisa
Last active November 9, 2015 18:12
Show Gist options
  • Save biglovisa/f567a2bc95189a997932 to your computer and use it in GitHub Desktop.
Save biglovisa/f567a2bc95189a997932 to your computer and use it in GitHub Desktop.
React session
// Annotated Code -- CRUD with Rails-React
// Functions we get from the React framework will be marked with -> R!
// to get the full repo: `$ git clone git@github.com:applegrain/ideabox-react.git`
// https://facebook.github.io/react/docs/thinking-in-react.html
// Good read to get into the React state of mind
// Create a new dashboard component.
var Dashboard = React.createClass({
// R! Declare the initial state of our component. Here we have one initial state,
// that we can access by `this.state.value`
// `this` in that case is this component, the dashboard component
getInitialState: function() {
return {value: 'Come join us', rawIdeas: []}
},
onButtonBoxClick: function() {
// R! whenever we want to modify or update our state we use `this.setState({});..`
// Here, we are changing the value of `this.state.value`
// The parts of our program where we are referencing `this.state.value` will
// listen for a change and simply rerender when there is a change
// Read about React's diffing algorithm to know more in detail how it knows what to render
this.setState({value: "You clicked a button, and here I am all of a sudden."});
},
// R! This function will execute when the component is mounted
// We only want to make a call to our server on page load
componentDidMount: function() {
$.ajax({
url: '/api/v1/ideas.json',
type: 'GET',
success: function(response) {
// update the value of our `rawIdeas` state and set it equal to the response object
// if you put `console.log(this.state.rawIdeas)` in the component, you will see
// that first it is an `[]` and almost immediately thereafter it will be an
// array with all of our ideas --> [Object, Object, Object...]
this.setState({rawIdeas: response});
}.bind(this)
});
},
handleDeleteIdea: function(id) {
// get an array of all the ideas minus the one we are going to delete
var ideasToKeep = this.state.rawIdeas.filter(function(idea) {
return idea.id != id;
});
// make an ajax call to our Rails API to delete the idea from our DB matching the given id
$.ajax({
url: '/api/v1/ideas/' + id,
type: 'DELETE',
success: function() {
// on success, update the state with the ideasToKeep array
this.setState({rawIdeas: ideasToKeep})
}.bind(this)
});
},
handleSubmitIdea: function(title, description) {
// send an ajax to our server, send a data object with our idea title and idea body
$.ajax({
url: '/api/v1/ideas',
type: 'POST',
data: {idea: {title: title, body: description}},
success: function(response) {
// on success, delegate to the renderAllIdeas function and pass in the response
// (which will be the idea we just created)
this.renderAllIdeas(response);
}.bind(this)
});
},
renderAllIdeas: function(newIdea) {
// create a new copy of the ideas array, adding the newIdea to it
var newIdeas = this.state.rawIdeas.concat(newIdea);
// update and set the state to the newIdeas array
this.setState({rawIdeas: newIdeas});
},
// R! The Render function of the component is what is being called on page load
// in the render function we can put logic as well. If you want to keep much of the
// logic in the render function or in functions above is up to you and the design of
// your program.
render: function() {
// R! The return statement is what will render on the DOM. Here we write JSX,
// HTML mixed with JavaScript. Our JS needs to be enclosed in `{}`
// A component only renders one element on the dom (at least in React-Rails) so
// we need to enclose all elements in a single div
return (
// `class` is a keyword so we declare our CSS selectors with `className`
// Below we render three other React components and we give them one props each
// A component can have as many props as you see fit and they are not comma separated
// As you can see, a prop can have a function reference as its value `this.onButtonBoxClick`
// This is how events in child components trigger function execution at the top level
<div className='dashboard'>
<h1>Preparation is key!!!!</h1>
<ButtonBox onButtonClick={this.onButtonBoxClick} />
<ContentBox text={this.state.value} />
<CreateNewIdea submitNewIdea={this.handleSubmitIdea} />
<IdeaBox ideas={this.state.rawIdeas} onDeleteIdea={this.handleDeleteIdea} />
</div>
)
}
});
var CreateNewIdea = React.createClass({
// when we click the `submit` button, we will hit this function
// we prevent the default button event (which would be a refresh I think)
// find the title and the description by HTML refs (R! React.findDOMNode is built in)
handleSubmit: function(event) {
event.preventDefault();
var title = (React.findDOMNode(this.refs.title).value.trim());
var description = (React.findDOMNode(this.refs.description).value.trim());
// execute the function reference passed down to the child as props, pass in the title
// and the description
this.props.submitNewIdea(title, description);
},
render: function() {
return (
<div>
<h1>Do you have another idea?</h1>
<form>
<div className="form-group dropdown-toggle">
<input type="text" ref="title" placeholder="title" id="searchfield" />
<input type="text" ref="description" placeholder="description" id="searchfield" />
<button name="button" onClick={ this.handleSubmit } className="btn btn-primary">Search</button>
</div>
</form>
</div>
)
}
});
// Another component
var ButtonBox = React.createClass({
handleClick: function() {
this.props.onButtonClick()
},
render: function() {
return (
// R! Here we have a click event. When this button is clicked it will go to
// the `handleClick` function in this component and execute the function reference
// that was passed down to this component as a prop
<div>
<button onClick={this.handleClick} >
Click me!
</button>
</div>
)
}
});
// Another component
// Nothing interesting going on here, it just renders its prop that is passed down
// from its parent
var ContentBox = React.createClass({
render: function() {
return (
<div className='content-box'>
<h1>{this.props.text}</h1>
</div>
)
}
});
// Another component
var IdeaBox = React.createClass({
// execute the function reference passed down to the child component as props
// pass in the value (which we have set to the idea's id) as an argument so
// we know which button it is that we want to click
handleDeleteClick: function(event) {
this.props.onDeleteIdea(event.target.value);
},
render: function() {
// Here we have some logic in the render function
// Our child components stay dumb and just receive all the data they need
// As we saw in the session, when we tried to make this component in charge
// of fetching the ideas from our Rails API, we ended up with a mess. If you are
// asking someone to drive a car, only give them the keys - and not keys, a hat and a pen.
// We iterate over `this.props.ideas` (which is `[]` for an instant and then `[Object, Object, Object...]`)
// `.map` returns a new array and we store it in the local variable `ideaElements`
// ideaElements will be an array with elements, the elements will be JSX divs
var ideaElements = this.props.ideas.map(function(idea, index) {
return (
<div className='idea' key={index} >
<h1>{idea.title}</h1>
<h3>{idea.body}</h3>
<p>Quality: {idea.quality}</p>
//a button with an `onClick` listener on
<button className='btn btn-primary'
onClick={this.handleDeleteClick}
value={idea.id}>
Delete!
</button>
</div>
)
});
return (
// Here we render the array of divs we built a few lines up
<div>
{ideaElements}
</div>
)
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment