react之todoList基础小项目

1.项目最终成品和项目目录快照如图:

2.context.js文件

// 使用context进行多级传递数据
// 1. createContext 创建一个可以多级传递的context数据
// 2. 使用 上一步创建的 conext ,提供一个 Provider 的提供器组件,把想要使用 context里面的数据的组件包起来,用来发送数据
// 3. 在需要使用 context里面的数据的后代组件里面使用 Consumer 的组件来进行数据的获取
// Consumer只能使用函数的方式返回一个jsx结构来进行数据的渲染
import { createContext } from "react";

// context里面的默认数据
const defVal = (id) => {};
const TodoContext = createContext(defVal); //defVal 作用是 约定数据的格式

export default TodoContext;

 

3.Todo.jsx文件

// 这是最外层的组件
import React, { Component } from "react";
import TodoAdd from "./TodoAdd";
import TodoList from "./TodoList";
import "./todo.css";
// 导入 TodoContext
import TodoContext from "./context";
const { Provider, Consumer } = TodoContext;

// 父传子
// 1.自定义属性,2.在子组件里面使用props接收

// 子传父
// 1.自定义属性把一个可以修改父组件数据的方法传递给子组件
// 2.在子组件里面调用父组件传递进来方法来把数据传递回来

let id = 2;

export default class Todo extends Component {
  constructor(props) {
    super(props);
    this.state = {
      list: [
        { id: 1, content: "明天要下大雨", isDone: false },
        { id: 2, content: "后天下太阳", isDone: true },
      ],
    };
  }
  add(newVal) {
    //   得到原来的数据
    const list = this.state.list;
    // 修改过后
    list.push({ id: ++id, content: newVal, isDone: false });
    // 把新的数据set回去
    this.setState({
      list,
    });
  }
  //   用于删除的方法
  remove(id) {
    // 根据id得到数据对应的索引
    // Array.prototype.findIndex(item=>条件), 得到满足条件的第一个元素的索引
    const idx = this.state.list.findIndex((item) => item.id === id);
    // 根据索引使用splice方法删除
    const list = this.state.list;
    list.splice(idx, 1);
    this.setState({ list });
  }
  render() {
    return (
      <Provider value={this.remove.bind(this)}>
        {/* <Consumer>
          {(val) => {
            return <div>{val.length}</div>;
          }}
        </Consumer> */}
        <div className="todo">
          <h1>TodoListDemo</h1>
          {/* 用于添加的子组件 */}
          <TodoAdd addFn={this.add.bind(this)} />
          {/* 两个列表 */}
          {/* 正在进行 */}
          <TodoList
            data={this.state.list.filter((item) => !item.isDone)}
            title="正在进行"
          />
          {/* 已经完成 */}
          <TodoList
            data={this.state.list.filter((item) => item.isDone)}
            title="已经完成"
          />
        </div>
      </Provider>
    );
  }
}

4.TodoAdd.jsx文件

// 实现添加功能的子组件
import React, { Component } from "react";
// 受控组件和非受控组件
// 受控 -- input表单受到state的控制

export default class TodoAdd extends Component {
  constructor(props) {
    super(props);
    console.log(this.props);
    this.state = {
      val: "",
    };
  }
  onClick() {
    // 修改父组件的数据 -- 子传父
    this.props.addFn(this.state.val);
    // 清空
    this.setState({ val: "" });
  }
  change(e) {
    //   把输入框的内容赋值给 state.val
    // 得到 内容
    // console.log(e.target.value);
    // 赋值
    this.setState({
      val: e.target.value,
    });
  }
  render() {
    return (
      <div className="add">
        <input
          type="text"
          value={this.state.val}
          onChange={this.change.bind(this)}
        />
        <button onClick={this.onClick.bind(this)}>添加</button>
      </div>
    );
  }
}

5.TodoList.jsx文件

// 两个列表的子组件
import React, { Component } from "react";
import TodoListItem from "./TodoListItem";

export default class TodoList extends Component {
  // props 就是我们从父组件传递进来的数据
  constructor(props) {
    super(props);
    // console.log(props);    this.s
  }
  render() {
    return (
      <div className="list">
        <h2>{this.props.title}</h2>
        <TodoListItem data={this.props.data} />
      </div>
    );
  }
}

6.TodoListItem.jsx文件

// 列表事件的子组件
import React, { Component } from "react";
import TodoContext from "./context";
const { Consumer } = TodoContext;

export default class TodoListItem extends Component {
  render() {
    return (
      <div>
        {this.props.data.map((item) => (
          <div className="item" key={item.id}>
            <input type="checkbox" checked={item.isDone} />
            <p>{item.content}</p>
            <Consumer>
              {(val) => <span onClick={() => val(item.id)}>删除</span>}
            </Consumer>
            {/* <Consumer>{(val) => <div>{typeof val}</div>}</Consumer> */}
          </div>
        ))}
      </div>
    );
  }
}

7.todo.css文件

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
.todo {
  width: 600px;
  box-shadow: 0 0 4px 2px #ccc, 0 0 4px 2px #ccc inset;
  margin: 100px auto;
  padding: 20px;
}
.add {
  display: flex;
  padding: 40px;
}
.add input {
  width: 400px;
  height: 40px;
  outline: none;
  border: 1px solid #ccc;
  padding: 0 20px;
}
.add button {
  width: 100px;
}
.list {
  padding: 20px;
}
.item {
  display: flex;
  align-items: center;
  border-bottom: 1px dashed #ccc;
}
.item p {
  flex: 1;
  line-height: 40px;
  padding-left: 20px;
}

 

posted @ 2022-04-09 08:57  李云蹊  阅读(38)  评论(0编辑  收藏  举报