前言
TodoList是一个前端学习很不错的案例,不管是用原生javascript,还是vue,React来实现TodoList的功能,在前端学习中都是很重要的,这篇文章用React来实现简单的一个TodoList案例
一、React项目初始
1.创建react初始项目
a.打开一个文件夹,进入cmd
b.输入 命令行 create-react-app + 文件名 创建一个react项目
c.项目创建成功
4.用编辑器打开该文件, 或者直接cmd进入该文件目录
输入命令行 npm start 启动React项目
cmd直接进入
从项目文件进
至此一个React项目就创建完成了
2.项目初始化
删除项目文件中所有不需要的文件资源
同时将App.js,index.js, index.html这几个文件中的无效代码删除干净
这样就可以看到一个空白的页面环境
二、搭建项目
1.页面布局
App.js文件
a.初始化App组件,简单设计组件布局
import React, { Fragment } from "react";
import { Component } from "react";
class App extends Component {
constructor(props) {
super(props);
}
render() {
return (
<Fragment>
<input></input>
<button>提交</button>
</Fragment>
);
}
}
export default App;
b.在 class 中,我们通过在构造函数中设置 this.state 并且初始化 { inputValue: ‘’, list: [] }
import React, { Fragment } from "react";
import { Component } from "react";
class App extends Component {
constructor(props) {
super(props);
this.state = {
inputValue: '121',
list: []
};
}
render() {
return (
<Fragment>
<input ></input>
<button>提交</button>
</Fragment>
);
}
}
export default App;
c.对input进行数据绑定,修改inputvalue的数据,input框中数据改变
import React, { Fragment } from "react";
import { Component } from "react";
class App extends Component {
constructor(props) {
super(props);
this.state = {
inputValue: 'yyy',
list: []
};
}
render() {
return (
<Fragment>
<input value={this.state.inputValue}></input>
<button>提交</button>
</Fragment>
);
}
}
export default App;
d.对input框绑定handlechange函数,看能否实现input框每次改变的时候值的获取。
import React, { Fragment } from "react";
import { Component } from "react";
class App extends Component {
constructor(props) {
super(props);
this.state = {
inputValue: 'yyy',
list: []
};
}
render() {
return (
<Fragment>
<input value={this.state.inputValue} onChange={this.handleChange}></input>
<button>提交</button>
</Fragment>
);
}
handleChange(e) {
alert(e.target.value);
}
}
export default App;
做到这儿我们也发现了,虽然弹窗弹出来了一个yy, 但是input框中依旧是yy,说明现在的input框中的值并不能由视图直接去改变,我们应该在handleChange函数中实现这样一个功能,可以通过改变input的value绑定的inputValue,来改变视图中input框中的值。
e.于是我们修改handleChange函数来实现这个功能
import React, { Fragment } from "react";
import { Component } from "react";
class App extends Component {
constructor(props) {
super(props);
this.state = {
inputValue: 'yyy',
list: []
};
}
render() {
return (
<Fragment>
<input
value={this.state.inputValue}
onChange={this.handleChange}></input>
<button>提交</button>
</Fragment>
);
}
handleChange(e) {
//alert(e.target.value);
this.setState(() => (
{
inputValue: e.target.value
}
));
}
}
export default App;
结果报错了
在React中,传递的事件参数不是一个字符串,而是一个实实在在的函数,代码中的handleChange()函数并不是我们主动调用的,而是触发onChange的事件时,react内部再去调用这个函数。而react的内部是不知道这里的this是指向哪里的,因此我们要自己通过bind改变事件方法的指向。
所以代码修改如下
import React, { Fragment } from "react";
import { Component } from "react";
class App extends Component {
constructor(props) {
super(props);
this.state = {
inputValue: 'yyy',
list: []
};
// 为了在回调中使用 `this`,这个绑定是必不可少的
this.handleChange = this.handleChange.bind(this)
}
render() {
return (
<Fragment>
<input
value={this.state.inputValue}
onChange={this.handleChange}></input>
<button>提交</button>
</Fragment>
);
}
handleChange(e) {
//alert(e.target.value);
this.setState(() => (
{
inputValue: e.target.value
}
));
}
}
export default App;
f.对state中list数据的渲染
import React, { Fragment } from "react";
import { Component } from "react";
class App extends Component {
constructor(props) {
super(props);
this.state = {
inputValue: 'yyy',
list: ['学习React', '学习英语']
};
// 为了在回调中使用 `this`,这个绑定是必不可少的
this.handleChange = this.handleChange.bind(this)
}
render() {
return (
<Fragment>
<input
value={this.state.inputValue}
onChange={this.handleChange}></input>
<button>提交</button>
<ul>
{this.state.list.map((item, index) => {
return (<div key={index}>{item}</div>)
})}
</ul>
</Fragment>
);
}
handleChange(e) {
//alert(e.target.value);
this.setState(() => (
{
inputValue: e.target.value
}
));
}
}
export default App;
g.实现点击提交按钮添加待办事件
import React, { Fragment } from "react";
import { Component } from "react";
class App extends Component {
constructor(props) {
super(props);
this.state = {
inputValue: 'yyy',
list: ['学习React', '学习英语']
};
// 为了在回调中使用 `this`,这个绑定是必不可少的
this.handleChange = this.handleChange.bind(this)
this.handleAdd = this.handleAdd.bind(this)
}
render() {
return (
<Fragment>
<input
value={this.state.inputValue}
onChange={this.handleChange}></input>
<button onClick={this.handleAdd}>提交</button>
<ul>
{this.state.list.map((item, index) => {
return (<div key={index}>{item}</div>)
})}
</ul>
</Fragment>
);
}
handleChange(e) {
//alert(e.target.value);
this.setState(() => (
{
inputValue: e.target.value
}
));
}
handleAdd() {
//preState是setState方法自带的参数,表示未修改前的State
this.setState((preState) => (
{
inputValue: '',
//...preState.list,是对未修改前的list进行展开
list: [...preState.list, preState.inputValue]
}
))
}
}
export default App;
h.点击待办事件实现删除功能
import React, { Fragment } from "react";
import { Component } from "react";
class App extends Component {
constructor(props) {
super(props);
this.state = {
inputValue: 'yyy',
list: ['学习React', '学习英语']
};
// 为了在回调中使用 `this`,这个绑定是必不可少的
this.handleChange = this.handleChange.bind(this);
this.handleAdd = this.handleAdd.bind(this);
this.handleDelete = this.handleDelete.bind(this);
}
render() {
return (
<Fragment>
<input
value={this.state.inputValue}
onChange={this.handleChange}></input>
<button onClick={this.handleAdd}>提交</button>
<ul>
{this.state.list.map((item, index) => {
return (
<li
key={index}
onClick={this.handleDelete}>
{item}
</li>)
})}
</ul>
</Fragment>
);
}
handleChange(e) {
//alert(e.target.value);
this.setState(() => (
{
inputValue: e.target.value
}
));
}
handleAdd() {
this.setState((preState) => (
{
inputValue: '',
list: [...preState.list, preState.inputValue]
}
))
}
handleDelete(index) {
this.setState((preState) => {
//immutable
//state不允许我们做任何改变
const list = [...preState.list];
list.splice(index, 1);
return {
list
}
})
}
}
export default App;
三、组件拆分
1.分析
通过分析,我们将下面的list单独拿出来放在一个组件Item中,所以我们新建一个Item.js文件,并将其引入到App.js文件中使用,其中我们涉及到了组件之间值的传递,和vue一样,父组件向子组件传值 也是通过 props 来传,在子组件中用 this.props.xx 接收父组件传来的值。
2.全部代码
index.js文件
import React, { Fragment } from "react";
import { Component } from "react";
import Item from "./Item";
class App extends Component {
constructor(props) {
super(props);
this.state = {
inputValue: 'yyy',
list: ['学习React', '学习英语']
};
// 为了在回调中使用 `this`,这个绑定是必不可少的
this.handleChange = this.handleChange.bind(this);
this.handleAdd = this.handleAdd.bind(this);
this.handleDelete = this.handleDelete.bind(this);
}
render() {
return (
<Fragment>
<input
value={this.state.inputValue}
onChange={this.handleChange}></input>
<button onClick={this.handleAdd}>提交</button>
<ul>
{this.getList()}
</ul>
</Fragment>
);
}
getList() {
return (
this.state.list.map((item, index) => {
return (
<div index={index}>
<Item item={item}
handleDelete={this.handleDelete}
key={index} />
</div>
)
})
)
}
handleChange(e) {
//alert(e.target.value);
this.setState(() => (
{
inputValue: e.target.value
}
));
}
handleAdd() {
this.setState((preState) => (
{
inputValue: '',
list: [...preState.list, preState.inputValue]
}
))
}
handleDelete(index) {
this.setState((preState) => {
//immutable
//state不允许我们做任何改变
const list = [...preState.list];
list.splice(index, 1);
return {
list
}
})
}
}
export default App;
item.js文件
import React, { Component, Fragment } from "react";
class Item extends Component {
constructor(props) {
super(props);
this.state = {};
this.handleClick = this.handleClick.bind(this);
}
render() {
return (
<Fragment>
<div onClick={this.handleClick}>{this.props.item}</div>
</Fragment>
)
}
handleClick() {
const { index, handleDelete } = this.props;
handleDelete(index);
}
}
export default Item
四、总结
学习了几天的React了,因为一些事,导致最近几天的进度放慢了。因为先学的Vue,觉得很多操作和vue的操作挺像的。但React的学习,让我慢慢喜欢上了看英文的文档,还有论坛。通过这个todolist案例,我对react的基础语法更熟练,对常见的问题也有了处理经验。希望通过这篇文章,大家可以了解React的基础操作,也欢迎大佬对我的代码提出修改意见,希望后面依旧可以坚持一周一篇博客,对已经学习的知识有个及时的输出,后面还会对之前学的JS基础,ES6的学习写些总结。