上次写了一个React生命周期详解,给新手看还是不是特别容易理解(其实我也是新手),这边再做一个React的todolist的dome做一个示例。我也是刚接触没多久React 希望大家共同进步!
下边直接上示例代码:
项目结构
我这里是用的webpack做的打包,每个人的习惯不一样,所以目录结构不必强求一样,只要自己理解就好。
app--|
|--components
| |-- Input
| | |--index.jsx
| | |--index.less
| |--List
| |--index.jsx
| |--index.less
|--containers
| |--TodoList
| |--index.jsx
|--index.jsx
|--index.html
示例代码
展示组件
Input子组件
// ../../components/Input/index
import React from 'react'
// 组件的样式文件
import './index.less'
class Input extends React.Component {
constructor(props, context) {
super(props, context)
this.state = {
// 初始化state
value: ''
}
}
handleChange(e) {
this.setState({
value: e.target.value
})
}
handleSubmit(e) {
let text = this.state.value;
// 判断是否是回车键 并且text不为空才提交text
if (e.keyCode == 13 && text.trim()) {
this.props.addTodoList (text);
// 提交后清空输入框value值
this.setSate({
value: ''
})
}
}
render() {
return(
<div className="header">
<input type="text" onKeyUp={this.handleSubmit.bind(this)} onChange={this.handleChange.bind(this)} value={this.state.value}/>
</div>
)
}
}
export default Input;
样式文件在此就不展示出来了。
这里需要说明一下我在学习时学到的几个知识点:
-
class类名
因为是class
在ES6中是定义类,所以在DOM中class
要写成className
- 给某个元素增加事件时最好是都带上
bind(this)
,例如:onChange={this.handleChange.bind(this)}
,因为在事件函数中一般都会使用到state
或者props
中的属性或者方法,虽然有的时候也许用不到,不过还是养成一个写上的习惯。 - 输入框的
value
值,一般如果你是默认携带的有值,不可以直接写value="xxx"
react会有这个值可能需要改变,这种写法在change中无法改变之类的警告, 如果真的需要有默认值可以写成defaultValue="xxxx"
。我这里是将state
中的value
赋值在input的属性里,然后通过input的onChange
来设置state
做到改变value值。这也是我在学习过程中在一个视频教程上讲到的约束性写法。
List子组件
// ../../components/List/index
import React from 'react'
import './index.less';
class List extends React.Component {
constructor(props, context) {
super(props, context)
}
handleClick(id){
this.props.deleteItem(id)
}
render() {
let todos = this.props.todos ? this.props.todos : [];
return (
<div className="list-content">
<ul className="list">
{
todos.map((item, index) => {
return (
<li key={index} className="item">
{item.text}
<span className="delete-btn" onClick={this.handleClick.bind(this, item.id)}>X</span>
</li>
)
})
}
</ul>
</div>
)
}
}
export default List;
业务组件
TodoLIst组件
// ./containers/TodoList/index
import React from 'react'
import Input from '../../components/Input/index';
import List from '../../components/List/index';
class TodoList extends React.Component {
constructor(props, context) {
super(props, context)
this.state = {
todos: []
}
}
// 删除单挑数据
deleteItem(id) {
let data = this.state.todos;
this.setState({
todos: data.filter((item, index) => {
if (item.id !== id) {
return item;
}
})
})
}
// 添加单条数据
addTodoList(value) {
const id = Date.now();
this.setState({
todos: this.state.todos.concat({
id: id,
text: value
})
})
}
render() {
return (
<div>
<Input addTodoList={this.addTodoList.bind(this)} />
<List todos={this.state.todos} deleteItem={this.deleteItem.bind(this)} />
</div>
)
}
};
export default TodoList;
这里的展示组件,业务组件我说一下我的理解:
- 展示组件:负责页面的渲染,效果展示。其数据来源是业务组件传递过来的
props
,或者自身的state
,其处理函数都由业务组件定义的函数通过props
传递过来,在自身函数中与业务组件做数据交互。 - 业务组件: 负责与服务器做ajax请求、数据的获取、业务逻辑的定义等业务交互。例如本案例的添加数据的函数,删除数据的函数都是在TodoList组件定义好 ,传递给对应的子组件。而List列表的数据也是由这个组件传递过去的。
入口文件
// index.jsx
import { render } from 'react-dom';
// 公共样式
import './static/css/common.less'
import TodoList from './containers/TodoList/index'
render(
<TodoList />,
document.getElementById('root')
)
// index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>react todo list</title>
</head>
<body>
<div id="root"></div>
</body>
</html>