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; }