react->Context笔记
此文章想记录一下react的context的使用以便于以后的复习
先附上我的目录
第一步在context.js上写下这样的代码:
context.js
import React from 'react' const MyContext = React.createContext( 'defalut' ) export default MyContext
第二步在TodoList.js里把context.js引进来,然后再把要传给子组件用的方法和数据赋值到context.js上
TodoList.js
1 import React, { Component } from 'react' 2 import TodoForm from './TodoForm' 3 import TodoContent from './TodoContent' 4 import MyContext from '../context' // 把context.js引进来 5 class TodoList extends Component { 6 constructor () { 7 super () 8 this.state = { 9 checkedAll:false, 10 datalist: [ 11 { 12 id: Date.now(), 13 title: "明年实现月薪过万", 14 done: false, 15 selected: false 16 }, 17 { 18 id: Date.now() + 10, 19 title: "男同学变成高富帅,迎娶白富美", 20 done: false, 21 selected: false 22 }, 23 { 24 id: Date.now() + 20, 25 title: "女同学变成白富美,迎娶高富帅", 26 done: false, 27 selected: false 28 } 29 ] 30 } 31 this.addItem = this.addItem.bind( this ) 32 this.removeItem = this.removeItem.bind( this ) 33 this.completeItem = this.completeItem.bind( this ) 34 this.selecteItem = this.selecteItem.bind( this ) 35 this.selectedAll = this.selectedAll.bind( this ) 36 37 } 38 addItem ( title ) { // 添加事项 39 let datalist = this.state.datalist 40 datalist.unshift( 41 { 42 id: Date.now() + 20, 43 title, 44 done: false, 45 selected: false 46 } 47 ) 48 this.setState({ datalist }) 49 } 50 removeItem ( id ) { // 删除事项 51 // let datalist = this.state.datalist.filter( item => item.id !== id ) 52 this.setState({ datalist: this.state.datalist.filter( item => item.id !== id ) }) 53 } 54 completeItem ( id ) { // 变成完成事项 55 let datalist = this.state.datalist.map( item => { 56 if ( item.id === id ) { 57 item.done = !item.done 58 } 59 return item 60 }) 61 this.setState( { datalist } ) 62 } 63 selecteItem ( id ) { // 改变check状态 64 let datalist = this.state.datalist.map( item => { 65 if ( item.id === id ) { 66 item.selected = !item.selected 67 } 68 return item 69 }) 70 this.setState( { datalist, checkedAll: datalist.every( item => item.selected ) } ) 71 } 72 selectedAll () { // 全选 73 let checkedAll = !this.state.checkedAll 74 let datalist = this.state.datalist.map( item => { 75 item.selected = checkedAll 76 return item 77 }) 78 this.setState( { checkedAll,datalist } ) 79 } 80 render () { 81 let {selecteItem,removeItem,completeItem,addItem} = this 82 let { datalist, checkedAll } = this.state 83 return ( 84 <div> 85 <MyContext.Provider value = { { selecteItem,removeItem,completeItem,addItem } }> // 将需要的方法传到MyContext里传递,那么就不用一个个传递到子组件这么麻烦了,但是使用context会使组件复用性变差 86 <TodoForm 87 addItem = { addItem } 88 ></TodoForm> 89 <TodoContent 90 selectedAll = { this.selectedAll } 91 datalist = { datalist } 92 checkedAll = { checkedAll } 93 > 94 </TodoContent> 95 </MyContext.Provider> 96 97 </div> 98 ) 99 } 100 } 101 export default TodoList
TodoList的子组件有TodoContent.js和TodoForm.js
TodoContent.js
1 import React from 'react' 2 import PropTypes from 'prop-types' 3 import TodoItem from './TodoItem' 4 function TodoContent ( props ) { 5 console.log( 'TodoContent.props', props ) 6 return ( 7 <> 8 <table> 9 <thead> 10 <tr> 11 <th><input type = 'checkbox' checked = { props.checkedAll } onChange = { props.selectedAll } />全选</th> 12 <th>#</th> 13 <th>待办事项</th> 14 <th>是否完成</th> 15 <th>操作</th> 16 </tr> 17 </thead> 18 <tbody> 19 { 20 props.datalist.map( (item,idx) => { 21 return ( 22 <TodoItem 23 key = { item.id } 24 data = { item } 25 idx = { idx } 26 > 27 </TodoItem> 28 ) 29 } ) 30 } 31 </tbody> 32 </table> 33 <div>总数:{props.datalist.length},完成:{props.datalist.filter( item => item.done).length},未完成:{props.datalist.filter( item => !item.done).length}</div> 34 </> 35 ) 36 } 37 TodoContent.propTypes = { 38 datalist: PropTypes.array.isRequired 39 } 40 TodoContent.defaultProps = { 41 datalist: [] 42 } 43 export default TodoContent
TodoItem.js(TodoContent.js的子组件)
1 import React from 'react' 2 import MyContext from '../context' 3 import Button from './TodoButton' 4 function TodoItem({ data, idx }) { 5 return ( 6 <MyContext.Consumer> // 使用此标签来把context的值传进来,那么函数组件就可以使用这样的方式来接受context父组件传过来的方法了,相当于vue的bus总线一样,只不过react的写法多端 7 { 8 value => { 9 let { selecteItem,removeItem,completeItem } = value 10 return ( 11 <tr> 12 <td> 13 <input type='checkbox' checked={data.selected} onChange={selecteItem.bind(null, data.id)} /> 14 </td> 15 <td>{idx + 1}</td> 16 <td>{data.title}</td> 17 <td>{data.done ? '是' : '否'}</td> 18 <td> 19 <Button onClick={completeItem.bind(null, data.id)}>完成</Button> 20 <Button onClick={removeItem.bind(null, data.id)}>删除</Button> 21 </td> 22 </tr> 23 ) 24 } 25 } 26 </MyContext.Consumer> 27 ) 28 } 29 export default TodoItem
TodoButton.js(TodoItem.js的子组件)
能够获取到父组件传进来的文字和事件,
1 import React from 'react' 2 const TodoButton = props => { 3 // console.log('Button:',props.children,React.Children, 'props->',props,'React->',React); 4 React.Children.forEach(props.children,function(item,idx){ 5 // console.log(item,idx,'BUTTON出来的') 6 }) 7 return ( 8 <button onClick = { props.onClick }>{ props.children }</button> 9 ) 10 } 11 export default TodoButton
TodoForm.js(TodoList的子组件)
TodoForm.js是类组件,有自己的状态也有this,所以可以这么写,通过TodoForm.contextType = MyContext,就能在类组件使用this.context.xxx()使用context的方法了
1 import React, { Component } from 'react' 2 import MyContext from '../context' 3 export default class TodoForm extends Component { 4 constructor(props) { 5 super(props) 6 this.state = { 7 title: '' 8 } 9 this.changeTitle = this.changeTitle.bind( this ) 10 this.additem = this.additem.bind( this ) 11 this.enter = this.enter.bind( this ) 12 } 13 changeTitle(event) { 14 this.setState({ title: event.target.value }) 15 } 16 additem() { 17 let title = this.state.title 18 if ( String( title ).trim() === "" ) { 19 alert( '事项名称必填!' ) 20 return 21 } 22 this.context.addItem( title ) 23 console.log('title->', title) 24 this.setState({ title: '' }) 25 this.eles.focus() 26 } 27 enter(event) { 28 if (event.which === 13) { 29 this.additem() 30 } 31 } 32 render() { 33 return ( 34 <div> 35 <input 36 type='text' 37 ref = { ele => this.eles = ele} 38 value = { this.state.title } 39 onChange = { this.changeTitle } 40 onKeyPress = { this.enter } 41 /> 42 <button onClick={this.additem}>添加</button> 43 </div> 44 ) 45 } 46 } 47 TodoForm.contextType = MyContext
函数组件和类组件有所区别
因为class组件有this,所以可以使用this.context,而this.context是react里面自带,可以来获取context的值
但是函数组件没有this,只能使用Consumer来获取context的值,但是Consumer是class类组件和函数组件都能用的
所以使用context的方式也有所区别。
如果我哪里不对,希望大家纠正