03 what's your name!
var test = (<div>
<p>Hey there. Enter your name.</p>
<input type="text" name="name" onChange={this.onNameChange} />
</div>);
if(this.state.name.length === 0)
return test;
else{
return (
<div>
<p>Hello {this.state.name}</p>
<input type="text" name="name" onChange={this.onNameChange} />
</div>
);
}
05 GroceryList 01
Properties are a way to pass parameters to your React components.Properties are to React components what attributes are to HTML elements.
state 更像是把值赋给一个组件,通常初始一个state,然后父组件像这样子<component test={this.state.xx} key={index}/>
然后子组件就可以return(<p key={this.props.key}>{this.props.test.xx}</p> )
渲染了,就基本是这个套路。
class GroceryList extends React.Component {
constructor(props) {
super(props);
this.state = {
groceries: [ { name: "Apples" } ]
};
}
render() {
let groceriesComponents = [];
// Properties are a way to pass parameters to your React components.
// We mentioned this in the third exercise. Properties are to React
// components what attributes are to HTML elements.
//
// Below you can see how to pass properties to child components.
// We have defined a `grocery` property for each `GroceryListItem`.
for(var index = 0; index < this.state.groceries.length; index++) {
groceriesComponents.push(
<GroceryListItem
grocery={this.state.groceries[index]}
key={index}
/>
);
}
// Hint: Don't forget about putting items into `ul`
return (
<div>
// Put your code here
<ul>
{groceriesComponents}
</ul>
</div>
);
}
}
// Render grocery name from component's properties.
// If you have a problem, check `this.props` in the console.
class GroceryListItem extends React.Component {
constructor(props) {
super(props);
}
render() {
// Put your code here.
return(
<li key={this.props.key}>{this.props.grocery.name}</li>
)
}
}
05 GroceryList 02
通过这个练习基本熟悉了state
的用法,首先state
一般用于设置初始值,然后通过setState({key:val})
设置,注意,这里只要一使用setState就会触发重新渲染render()方法,然后在后续组件中想办法使之改变。
(遇到问题想办法解决,一步一步来,注意看浏览器报错.使用console.log
来打印每一步的状态)
var React = require("react");
// We continue our journey with reactive grocery list. We implemented the previous
// task ourselves. You can see our example implementation.
//
// Task: You have to implement adding items to the list. Create the implementation
// of the `addGroceryItem` method. This method should modify the `GroceryList`
// component's state and by that re-render this component.
//
// You need to render an input and button in `GroceryList` (after the
// groceries list). Users will use them as an input for new groceries.
//
// We prepared two components for you. Please render the button and
// input under your list and define the `onClick` handler for the button.
//
// Hint: See `render` method body. Look for `newProductInput` and
// `newProductAddButton` variables
//
// Do you remember how we used `onChange` event in the third exercise?
// 问题1 到底是拼接之后还是替换
// 问题2 先实现改变就回显的功能,现在是只要光标以改变就会重新setState
class GroceryList extends React.Component {
constructor(props) {
super(props);
this.state = {
groceries: [
{ name: "Apples" }
],
newGroceryName: ""
};
// 这里的bind 是几个意思??
this.addGroceryItem = this.addGroceryItem.bind(this);
this.inputChanged = this.inputChanged.bind(this);
}
// Warning: You shouldn't change this method
inputChanged(event) {
this.setState({newGroceryName: event.target.value});
}
// Fill the definition of the following method to allow adding new items to the list
// Hint #1: You should use the `concat` function to modify groceries list.
// Hint #2: Remember about the case where input is empty.
// Hint #3: Name of the new grocery item will be stored in `this.state.newGroceryName`.
addGroceryItem() {
// Put your code here
//console.log(this.state);
if(this.state.newGroceryName){
var groceriesVal= this.state.groceries.concat({'name':this.state.newGroceryName});
this.setState({groceries:groceriesVal})
}
}
render() {
let groceriesComponents = [],
newProductInput,
newProductAddButton;
for(var index = 0; index < this.state.groceries.length; index++) {
groceriesComponents.push(
<GroceryListItem
grocery={this.state.groceries[index]}
/>
);
}
// Here are components for task #2.
newProductInput = <input className='new-item' type="text" onChange={this.inputChanged}/>;
// Something is missing here... Will anything happen if you click this button now?
newProductAddButton = <button className='add-product' onClick={this.addGroceryItem}>Add new Product</button>;
return (
<div>
<ul>
{groceriesComponents}
{newProductInput}
{newProductAddButton}
</ul>
</div>
);
}
}
class GroceryListItem extends React.Component {
constructor(props) {
super(props);
}
render() {
return (<li>{this.props.grocery.name}</li>);
}
}
export default GroceryList;
todolist
任务相当于做一个类似于todolist的东西,点击改变样式.
思路是给每个li绑定点击事件,然后反转这个li下的complete属性,最后自然是setState。难点是可能没有想到给每个item 加index 导致无法绑定。多思考,多看提示会少踩坑
(这段代码没有写出来,主要原因是因为不理解bind方法,然后没有理解传参那一步。)
class GroceryList extends React.Component {
constructor(props) {
super(props);
this.state = {
groceries: [
{
name: "Apples",
completed: false
}
],
newGroceryName: ""
};
this.addGroceryItem = this.addGroceryItem.bind(this);
this.clearList = this.clearList.bind(this);
this.inputChanged = this.inputChanged.bind(this);
}
inputChanged(event) {
this.setState({ newGroceryName: event.target.value });
}
addGroceryItem() {
if(this.state.newGroceryName) {
let newGroceryItem = { name: this.state.newGroceryName };
this.setState({
groceries: this.state.groceries.concat([newGroceryItem])
});
}
}
clearList(event) {
this.setState({groceries: []});
}
// Fill the definition of the following method to allow completing each item
// Hint 1: Pay attention to the element's index on the list.
toggleGroceryCompleteness(groceryIndex) {
var groceryCompleted = this.state.groceries[groceryIndex].completed;
var grocery = this.state.groceries[groceryIndex];
grocery.completed = !grocery.completed;
this.setState({
groceries: this.state.groceries
})
}
render() {
let groceriesComponents = [],
newProductInput,
newProductAddButton,
clearListButton;
for(var index = 0; index < this.state.groceries.length; index++) {
groceriesComponents.push(
<GroceryListItem
grocery={this.state.groceries[index]}
onComplete={this.toggleGroceryCompleteness.bind(this, index)}
/>
);
}
//不理解bind(this)有什么用 onComplete={this.toggleGroceryCompleteness.bind(this, index)} 黑人问号???!!!
// 上面那个方法调用好像是指将这个方法绑定到这个元素上,传进变量index!!! 注意理解
// 这道题到底是要干嘛啊?给每个属性加了一个complete属性。每个 li 上有个onComplete事件,点击之后如何切换?
// 大概意思好像是点击li 标签,实现该元素下complete的切换
newProductInput = <input className='new-item' type="text" onChange={this.inputChanged}/>;
newProductAddButton = <button className='add-product' onClick={this.addGroceryItem}>Add new Product</button>;
clearListButton = <button className='clear-list' onClick={this.clearList}>Clear the List</button>;
return (
<div>
<ul>
{groceriesComponents}
</ul>
{newProductInput}
{newProductAddButton}
{clearListButton}
</div>
);
}
}
class GroceryListItem extends React.Component {
constructor(props) {
super(props);
}
render() {
//这个complete主要是切换属性 onClick方法是怎么回事?父元素中有一个onComplete方法
let completed = this.props.grocery.completed ? "completed" : '';
//console.log(completed);
return (
<li className={completed} onClick={this.props.onComplete}>
{this.props.grocery.name}
</li>
);
}
}