Last active
November 9, 2015 18:12
-
-
Save biglovisa/f567a2bc95189a997932 to your computer and use it in GitHub Desktop.
React session
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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 [email protected]: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